pax_global_header00006660000000000000000000000064121771725720014525gustar00rootroot0000000000000052 comment=67373f55cb04e683f1558e079908a2e1e13cc412 dxx-rebirth-0.58.1-d1x/000077500000000000000000000000001217717257200145525ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/.gitignore000066400000000000000000000011071217717257200165410ustar00rootroot00000000000000# Compiled source # ################### *.com *.class *.dll *.exe *.app *.o *.so *.pyc build # Packages # ############ # it's better to unpack these files and commit the raw source # git has its own built in compression methods *.7z *.dmg *.gz *.iso *.jar *.rar *.tar *.zip # Logs and databases # ###################### *.log *.sql *.sqlite *.dblite # OS generated files # ###################### .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes Icon? ehthumbs.db Thumbs.db # Xcode generated files # ###################### # Note: committing these is optional *.mode1v3 *.pbxuserdxx-rebirth-0.58.1-d1x/2d/000077500000000000000000000000001217717257200150575ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/2d/2dsline.c000066400000000000000000000043441217717257200165700ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for drawing solid scanlines. * */ #include #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "dxxerror.h" void gr_linear_darken(ubyte * dest, int darkening_level, int count, ubyte * fade_table) { register int i; for (i=0;icv_fade_level >= GR_FADE_OFF) { switch(TYPE) { case BM_LINEAR: #ifdef OGL case BM_OGL: #endif gr_linear_stosd( DATA + ROWSIZE*y + x1, (unsigned char)COLOR, x2-x1+1); break; } } else { switch(TYPE) { case BM_LINEAR: #ifdef OGL case BM_OGL: #endif gr_linear_darken( DATA + ROWSIZE*y + x1, grd_curcanv->cv_fade_level, x2-x1+1, gr_fade_table); break; } } } void gr_scanline( int x1, int x2, int y ) { if ((y<0)||(y>MAXY)) return; if (x2 < x1 ) x2 ^= x1 ^= x2; if (x1 > MAXX) return; if (x2 < MINX) return; if (x1 < MINX) x1 = MINX; if (x2 > MAXX) x2 = MAXX; if (grd_curcanv->cv_fade_level >= GR_FADE_OFF) { switch(TYPE) { case BM_LINEAR: #ifdef OGL case BM_OGL: #endif gr_linear_stosd( DATA + ROWSIZE*y + x1, (unsigned char)COLOR, x2-x1+1); break; } } else { switch(TYPE) { case BM_LINEAR: #ifdef OGL case BM_OGL: #endif gr_linear_darken( DATA + ROWSIZE*y + x1, grd_curcanv->cv_fade_level, x2-x1+1, gr_fade_table); break; } } } dxx-rebirth-0.58.1-d1x/2d/bitblt.c000066400000000000000000000406421217717257200165110ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for bitblt's. * */ #include #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "rle.h" #include "dxxerror.h" #include "byteswap.h" #ifdef OGL #include "ogl_init.h" #endif int gr_bitblt_dest_step_shift = 0; int gr_bitblt_double = 0; ubyte *gr_bitblt_fade_table=NULL; void gr_bm_ubitblt00_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_bm_ubitblt00m_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_bm_ubitblt0x_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest, int masked); void gr_bm_ubitblt01(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_bm_ubitblt02(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_linear_movsd( ubyte * source, ubyte * dest, unsigned int nbytes) { memcpy(dest,source,nbytes); } void gr_linear_rep_movsdm(ubyte *src, ubyte *dest, int num_pixels) { register ubyte c; while (num_pixels--) if ((c=*src++)!=255) *dest++=c; else dest++; } void gr_linear_rep_movsdm_faded(ubyte * src, ubyte * dest, int num_pixels, ubyte fade_value ) { register ubyte c; while (num_pixels--) if ((c=*src++)!=255) *dest++=gr_fade_table[((int)fade_value<<8)|(int)c]; else dest++; } void gr_linear_rep_movsd_2x(ubyte * source, ubyte * dest, uint nbytes ) { register ubyte c; while (nbytes--) { if (nbytes&1) *dest++=*source++; else { unsigned short *sp=(unsigned short *)dest; c=*source++; *sp=((short)c<<8)|(short)c; dest+=2; } } } void gr_ubitmap00( int x, int y, grs_bitmap *bm ) { register int y1; int dest_rowsize; unsigned char * dest; unsigned char * src; dest_rowsize=grd_curcanv->cv_bitmap.bm_rowsize << gr_bitblt_dest_step_shift; dest = &(grd_curcanv->cv_bitmap.bm_data[ dest_rowsize*y+x ]); src = bm->bm_data; for (y1=0; y1 < bm->bm_h; y1++ ) { if (gr_bitblt_double) gr_linear_rep_movsd_2x( src, dest, bm->bm_w ); else gr_linear_movsd( src, dest, bm->bm_w ); src += bm->bm_rowsize; dest+= (int)(dest_rowsize); } } void gr_ubitmap00m( int x, int y, grs_bitmap *bm ) { register int y1; int dest_rowsize; unsigned char * dest; unsigned char * src; dest_rowsize=grd_curcanv->cv_bitmap.bm_rowsize << gr_bitblt_dest_step_shift; dest = &(grd_curcanv->cv_bitmap.bm_data[ dest_rowsize*y+x ]); src = bm->bm_data; if (gr_bitblt_fade_table==NULL) { for (y1=0; y1 < bm->bm_h; y1++ ) { gr_linear_rep_movsdm( src, dest, bm->bm_w ); src += bm->bm_rowsize; dest+= (int)(dest_rowsize); } } else { for (y1=0; y1 < bm->bm_h; y1++ ) { gr_linear_rep_movsdm_faded( src, dest, bm->bm_w, gr_bitblt_fade_table[y1+y] ); src += bm->bm_rowsize; dest+= (int)(dest_rowsize); } } } void gr_ubitmap012( int x, int y, grs_bitmap *bm ) { register int x1, y1; unsigned char * src; src = bm->bm_data; for (y1=y; y1 < (y+bm->bm_h); y1++ ) { for (x1=x; x1 < (x+bm->bm_w); x1++ ) { gr_setcolor( *src++ ); gr_upixel( x1, y1 ); } } } void gr_ubitmap012m( int x, int y, grs_bitmap *bm ) { register int x1, y1; unsigned char * src; src = bm->bm_data; for (y1=y; y1 < (y+bm->bm_h); y1++ ) { for (x1=x; x1 < (x+bm->bm_w); x1++ ) { if ( *src != 255 ) { gr_setcolor( *src ); gr_upixel( x1, y1 ); } src++; } } } void gr_ubitmapGENERIC(int x, int y, grs_bitmap * bm) { register int x1, y1; for (y1=0; y1 < bm->bm_h; y1++ ) { for (x1=0; x1 < bm->bm_w; x1++ ) { gr_setcolor( gr_gpixel(bm,x1,y1) ); gr_upixel( x+x1, y+y1 ); } } } void gr_ubitmapGENERICm(int x, int y, grs_bitmap * bm) { register int x1, y1; ubyte c; for (y1=0; y1 < bm->bm_h; y1++ ) { for (x1=0; x1 < bm->bm_w; x1++ ) { c = gr_gpixel(bm,x1,y1); if ( c != 255 ) { gr_setcolor( c ); gr_upixel( x+x1, y+y1 ); } } } } void gr_ubitmap( int x, int y, grs_bitmap *bm ) { int source, dest; source = bm->bm_type; dest = TYPE; if (source==BM_LINEAR) { switch( dest ) { case BM_LINEAR: if ( bm->bm_flags & BM_FLAG_RLE ) gr_bm_ubitblt00_rle(bm->bm_w, bm->bm_h, x, y, 0, 0, bm, &grd_curcanv->cv_bitmap ); else gr_ubitmap00( x, y, bm ); return; #ifdef OGL case BM_OGL: ogl_ubitmapm_cs(x,y,-1,-1,bm,-1,F1_0); return; #endif default: gr_ubitmap012( x, y, bm ); return; } } else { gr_ubitmapGENERIC(x, y, bm); } } void gr_ubitmapm( int x, int y, grs_bitmap *bm ) { int source, dest; source = bm->bm_type; dest = TYPE; if (source==BM_LINEAR) { switch( dest ) { case BM_LINEAR: if ( bm->bm_flags & BM_FLAG_RLE ) gr_bm_ubitblt00m_rle(bm->bm_w, bm->bm_h, x, y, 0, 0, bm, &grd_curcanv->cv_bitmap ); else gr_ubitmap00m( x, y, bm ); return; #ifdef OGL case BM_OGL: ogl_ubitmapm_cs(x,y,-1,-1,bm,-1,F1_0); return; #endif default: gr_ubitmap012m( x, y, bm ); return; } } else { gr_ubitmapGENERICm(x, y, bm); } } // From Linear to Linear void gr_bm_ubitblt00(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { unsigned char * dbits; unsigned char * sbits; //int src_bm_rowsize_2, dest_bm_rowsize_2; int dstep; int i; sbits = src->bm_data + (src->bm_rowsize * sy) + sx; dbits = dest->bm_data + (dest->bm_rowsize * dy) + dx; dstep = dest->bm_rowsize << gr_bitblt_dest_step_shift; // No interlacing, copy the whole buffer. if (gr_bitblt_double) for (i=0; i < h; i++ ) { gr_linear_rep_movsd_2x( sbits, dbits, w ); sbits += src->bm_rowsize; dbits += dstep; } else for (i=0; i < h; i++ ) { gr_linear_movsd( sbits, dbits, w ); //memcpy(dbits, sbits, w); sbits += src->bm_rowsize; dbits += dstep; } } // From Linear to Linear Masked void gr_bm_ubitblt00m(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { unsigned char * dbits; unsigned char * sbits; //int src_bm_rowsize_2, dest_bm_rowsize_2; int i; sbits = src->bm_data + (src->bm_rowsize * sy) + sx; dbits = dest->bm_data + (dest->bm_rowsize * dy) + dx; // No interlacing, copy the whole buffer. if (gr_bitblt_fade_table==NULL) { for (i=0; i < h; i++ ) { gr_linear_rep_movsdm( sbits, dbits, w ); sbits += src->bm_rowsize; dbits += dest->bm_rowsize; } } else { for (i=0; i < h; i++ ) { gr_linear_rep_movsdm_faded( sbits, dbits, w, gr_bitblt_fade_table[dy+i] ); sbits += src->bm_rowsize; dbits += dest->bm_rowsize; } } } void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { int dx1=dx, dx2=dx+dest->bm_w-1; int dy1=dy, dy2=dy+dest->bm_h-1; int sx1=sx, sx2=sx+src->bm_w-1; int sy1=sy, sy2=sy+src->bm_h-1; if ((dx1 >= dest->bm_w ) || (dx2 < 0)) return; if ((dy1 >= dest->bm_h ) || (dy2 < 0)) return; if ( dx1 < 0 ) { sx1 += -dx1; dx1 = 0; } if ( dy1 < 0 ) { sy1 += -dy1; dy1 = 0; } if ( dx2 >= dest->bm_w ) { dx2 = dest->bm_w-1; } if ( dy2 >= dest->bm_h ) { dy2 = dest->bm_h-1; } if ((sx1 >= src->bm_w ) || (sx2 < 0)) return; if ((sy1 >= src->bm_h ) || (sy2 < 0)) return; if ( sx1 < 0 ) { dx1 += -sx1; sx1 = 0; } if ( sy1 < 0 ) { dy1 += -sy1; sy1 = 0; } if ( sx2 >= src->bm_w ) { sx2 = src->bm_w-1; } if ( sy2 >= src->bm_h ) { sy2 = src->bm_h-1; } // Draw bitmap bm[x,y] into (dx1,dy1)-(dx2,dy2) if ( dx2-dx1+1 < w ) w = dx2-dx1+1; if ( dy2-dy1+1 < h ) h = dy2-dy1+1; if ( sx2-sx1+1 < w ) w = sx2-sx1+1; if ( sy2-sy1+1 < h ) h = sy2-sy1+1; gr_bm_ubitblt(w,h, dx1, dy1, sx1, sy1, src, dest ); } void gr_bm_ubitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { register int x1, y1; if ( (src->bm_type == BM_LINEAR) && (dest->bm_type == BM_LINEAR )) { if ( src->bm_flags & BM_FLAG_RLE ) gr_bm_ubitblt00_rle( w, h, dx, dy, sx, sy, src, dest ); else gr_bm_ubitblt00( w, h, dx, dy, sx, sy, src, dest ); return; } #ifdef OGL if ( (src->bm_type == BM_LINEAR) && (dest->bm_type == BM_OGL )) { ogl_ubitblt(w, h, dx, dy, sx, sy, src, dest); return; } if ( (src->bm_type == BM_OGL) && (dest->bm_type == BM_LINEAR )) { return; } if ( (src->bm_type == BM_OGL) && (dest->bm_type == BM_OGL )) { return; } #endif if ( (src->bm_flags & BM_FLAG_RLE ) && (src->bm_type == BM_LINEAR) ) { gr_bm_ubitblt0x_rle(w, h, dx, dy, sx, sy, src, dest, 0 ); return; } for (y1=0; y1 < h; y1++ ) { for (x1=0; x1 < w; x1++ ) { gr_bm_pixel( dest, dx+x1, dy+y1, gr_gpixel(src,sx+x1,sy+y1) ); } } } // Clipped bitmap ... void gr_bitmap( int x, int y, grs_bitmap *bm ) { int dx1=x, dx2=x+bm->bm_w-1; int dy1=y, dy2=y+bm->bm_h-1; #ifndef OGL int sx=0, sy=0; #endif if ((dx1 >= grd_curcanv->cv_bitmap.bm_w ) || (dx2 < 0)) return; if ((dy1 >= grd_curcanv->cv_bitmap.bm_h) || (dy2 < 0)) return; if ( dx1 < 0 ) { #ifndef OGL sx = -dx1; #endif dx1 = 0; } if ( dy1 < 0 ) { #ifndef OGL sy = -dy1; #endif dy1 = 0; } if ( dx2 >= grd_curcanv->cv_bitmap.bm_w ) { dx2 = grd_curcanv->cv_bitmap.bm_w-1; } if ( dy2 >= grd_curcanv->cv_bitmap.bm_h ) { dy2 = grd_curcanv->cv_bitmap.bm_h-1; } // Draw bitmap bm[x,y] into (dx1,dy1)-(dx2,dy2) #ifdef OGL ogl_ubitmapm_cs(x, y, 0, 0, bm, -1, F1_0); #else gr_bm_ubitblt(dx2-dx1+1,dy2-dy1+1, dx1, dy1, sx, sy, bm, &grd_curcanv->cv_bitmap ); #endif } void gr_bitmapm( int x, int y, grs_bitmap *bm ) { int dx1=x, dx2=x+bm->bm_w-1; int dy1=y, dy2=y+bm->bm_h-1; int sx=0, sy=0; if ((dx1 >= grd_curcanv->cv_bitmap.bm_w ) || (dx2 < 0)) return; if ((dy1 >= grd_curcanv->cv_bitmap.bm_h) || (dy2 < 0)) return; if ( dx1 < 0 ) { sx = -dx1; dx1 = 0; } if ( dy1 < 0 ) { sy = -dy1; dy1 = 0; } if ( dx2 >= grd_curcanv->cv_bitmap.bm_w ) { dx2 = grd_curcanv->cv_bitmap.bm_w-1; } if ( dy2 >= grd_curcanv->cv_bitmap.bm_h ) { dy2 = grd_curcanv->cv_bitmap.bm_h-1; } // Draw bitmap bm[x,y] into (dx1,dy1)-(dx2,dy2) if ( (bm->bm_type == BM_LINEAR) && (grd_curcanv->cv_bitmap.bm_type == BM_LINEAR )) { if ( bm->bm_flags & BM_FLAG_RLE ) gr_bm_ubitblt00m_rle(dx2-dx1+1,dy2-dy1+1, dx1, dy1, sx, sy, bm, &grd_curcanv->cv_bitmap ); else gr_bm_ubitblt00m(dx2-dx1+1,dy2-dy1+1, dx1, dy1, sx, sy, bm, &grd_curcanv->cv_bitmap ); return; } gr_bm_ubitbltm(dx2-dx1+1,dy2-dy1+1, dx1, dy1, sx, sy, bm, &grd_curcanv->cv_bitmap ); } void gr_bm_ubitbltm(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { register int x1, y1; ubyte c; #ifdef OGL if ( (src->bm_type == BM_LINEAR) && (dest->bm_type == BM_OGL )) { ogl_ubitblt(w, h, dx, dy, sx, sy, src, dest); return; } if ( (src->bm_type == BM_OGL) && (dest->bm_type == BM_LINEAR )) { return; } if ( (src->bm_type == BM_OGL) && (dest->bm_type == BM_OGL )) { return; } #endif for (y1=0; y1 < h; y1++ ) { for (x1=0; x1 < w; x1++ ) { if ((c=gr_gpixel(src,sx+x1,sy+y1))!=255) gr_bm_pixel( dest, dx+x1, dy+y1,c ); } } } void gr_bm_ubitblt00_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { unsigned char * dbits; unsigned char * sbits; int i, data_offset; data_offset = 1; if (src->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &src->bm_data[4 + (src->bm_h*data_offset)]; for (i=0; ibm_data[4+(i*data_offset)])); dbits = dest->bm_data + (dest->bm_rowsize * dy) + dx; // No interlacing, copy the whole buffer. for (i=0; i < h; i++ ) { gr_rle_expand_scanline( dbits, sbits, sx, sx+w-1 ); if ( src->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(src->bm_data[4+((i+sy)*data_offset)]))); else sbits += (int)(src->bm_data[4+i+sy]); dbits += dest->bm_rowsize << gr_bitblt_dest_step_shift; } } void gr_bm_ubitblt00m_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest) { unsigned char * dbits; unsigned char * sbits; int i, data_offset; data_offset = 1; if (src->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &src->bm_data[4 + (src->bm_h*data_offset)]; for (i=0; ibm_data[4+(i*data_offset)])); dbits = dest->bm_data + (dest->bm_rowsize * dy) + dx; // No interlacing, copy the whole buffer. for (i=0; i < h; i++ ) { gr_rle_expand_scanline_masked( dbits, sbits, sx, sx+w-1 ); if ( src->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(src->bm_data[4+((i+sy)*data_offset)]))); else sbits += (int)(src->bm_data[4+i+sy]); dbits += dest->bm_rowsize << gr_bitblt_dest_step_shift; } } // in rle.c void gr_bm_ubitblt0x_rle(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest, int masked ) { int i, data_offset; register int y1; unsigned char * sbits; data_offset = 1; if (src->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &src->bm_data[4 + (src->bm_h*data_offset)]; for (i=0; ibm_data[4+(i*data_offset)])); for (y1=0; y1 < h; y1++ ) { gr_rle_expand_scanline_generic( dest, dx, dy+y1, sbits, sx, sx+w-1); if ( src->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(src->bm_data[4+((y1+sy)*data_offset)]))); else sbits += (int)src->bm_data[4+y1+sy]; } } // rescalling bitmaps, 10/14/99 Jan Bobrowski jb@wizard.ae.krakow.pl static inline void scale_line(unsigned char *in, unsigned char *out, int ilen, int olen) { int a = olen/ilen, b = olen%ilen; int c = 0, i; unsigned char *end = out + olen; while(out= ilen) { c -= ilen; goto inside; } while(--i>=0) { inside: *out++ = *in; } in++; } } void gr_bitmap_scale_to(grs_bitmap *src, grs_bitmap *dst) { unsigned char *s = src->bm_data; unsigned char *d = dst->bm_data; int h = src->bm_h; int a = dst->bm_h/h, b = dst->bm_h%h; int c = 0, i, y; for(y=0; y= h) { c -= h; goto inside; } while(--i>=0) { inside: scale_line(s, d, src->bm_w, dst->bm_w); d += dst->bm_rowsize; } s += src->bm_rowsize; } } void show_fullscr(grs_bitmap *bm) { grs_bitmap * const scr = &grd_curcanv->cv_bitmap; #ifdef OGL if(bm->bm_type == BM_LINEAR && scr->bm_type == BM_OGL && bm->bm_w <= grd_curscreen->sc_w && bm->bm_h <= grd_curscreen->sc_h) // only scale with OGL if bitmap is not bigger than screen size { ogl_ubitmapm_cs(0,0,-1,-1,bm,-1,F1_0);//use opengl to scale, faster and saves ram. -MPM return; } #endif if(scr->bm_type != BM_LINEAR) { grs_bitmap *tmp = gr_create_bitmap(scr->bm_w, scr->bm_h); gr_bitmap_scale_to(bm, tmp); gr_bitmap(0, 0, tmp); gr_free_bitmap(tmp); return; } gr_bitmap_scale_to(bm, scr); } // Find transparent area in bitmap void gr_bitblt_find_transparent_area(grs_bitmap *bm, int *minx, int *miny, int *maxx, int *maxy) { ubyte c; int i = 0, x = 0, y = 0, count = 0; static unsigned char buf[1024*1024]; if (!(bm->bm_flags&BM_FLAG_TRANSPARENT)) return; memset(buf,0,1024*1024); *minx = bm->bm_w - 1; *maxx = 0; *miny = bm->bm_h - 1; *maxy = 0; // decode the bitmap if (bm->bm_flags & BM_FLAG_RLE){ unsigned char * dbits; unsigned char * sbits; int i, data_offset; data_offset = 1; if (bm->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)]; dbits = buf; for (i=0; i < bm->bm_h; i++ ) { gr_rle_decode(sbits,dbits); if ( bm->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)]))); else sbits += (int)bm->bm_data[4+i]; dbits += bm->bm_w; } } else { memcpy(&buf, bm->bm_data, sizeof(unsigned char)*(bm->bm_w*bm->bm_h)); } for (y = 0; y < bm->bm_h; y++) { for (x = 0; x < bm->bm_w; x++) { c = buf[i++]; if (c == TRANSPARENCY_COLOR) { // don't look for transparancy color here. count++; if (x < *minx) *minx = x; if (y < *miny) *miny = y; if (x > *maxx) *maxx = x; if (y > *maxy) *maxy = y; } } } Assert (count); } dxx-rebirth-0.58.1-d1x/2d/bitmap.c000066400000000000000000000144631217717257200165070ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for manipulating grs_bitmaps. * */ #include #include #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "dxxerror.h" #ifdef OGL #include "ogl_init.h" #endif #include "bitmap.h" void gr_set_bitmap_data (grs_bitmap *bm, unsigned char *data) { #ifdef OGL ogl_freebmtexture(bm); #endif bm->bm_data = data; } grs_bitmap *gr_create_bitmap(int w, int h ) { return gr_create_bitmap_raw (w, h, d_malloc( MAX_BMP_SIZE(w, h) )); } grs_bitmap *gr_create_bitmap_raw(int w, int h, unsigned char * raw_data ) { grs_bitmap *new; new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) ); gr_init_bitmap (new, 0, 0, 0, w, h, w, raw_data); return new; } void gr_init_bitmap( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline, unsigned char * data ) // TODO: virtualize { bm->bm_x = x; bm->bm_y = y; bm->bm_w = w; bm->bm_h = h; bm->bm_flags = 0; bm->bm_type = mode; bm->bm_rowsize = bytesperline; bm->bm_data = NULL; #ifdef OGL bm->bm_parent=NULL;bm->gltexture=NULL; #endif gr_set_bitmap_data (bm, data); } void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline) { gr_init_bitmap(bm, mode, x, y, w, h, bytesperline, 0); gr_set_bitmap_data(bm, d_malloc( MAX_BMP_SIZE(w, h) )); } void gr_init_bitmap_data (grs_bitmap *bm) // TODO: virtulize { bm->bm_data = NULL; bm->bm_parent=NULL; #ifdef OGL bm->gltexture=NULL; #endif } grs_bitmap *gr_create_sub_bitmap(grs_bitmap *bm, int x, int y, int w, int h ) { grs_bitmap *new; new = (grs_bitmap *)d_malloc( sizeof(grs_bitmap) ); gr_init_sub_bitmap (new, bm, x, y, w, h); return new; } void gr_free_bitmap(grs_bitmap *bm ) { gr_free_bitmap_data (bm); if (bm!=NULL) d_free(bm); } void gr_free_sub_bitmap(grs_bitmap *bm ) { if (bm!=NULL) { d_free(bm); } } void gr_free_bitmap_data (grs_bitmap *bm) // TODO: virtulize { #ifdef OGL ogl_freebmtexture(bm); #endif if (bm->bm_data != NULL) d_free (bm->bm_data); bm->bm_data = NULL; } void gr_init_sub_bitmap (grs_bitmap *bm, grs_bitmap *bmParent, int x, int y, int w, int h ) // TODO: virtualize { bm->bm_x = x + bmParent->bm_x; bm->bm_y = y + bmParent->bm_y; bm->bm_w = w; bm->bm_h = h; bm->bm_flags = bmParent->bm_flags; bm->bm_type = bmParent->bm_type; bm->bm_rowsize = bmParent->bm_rowsize; #ifdef OGL bm->gltexture=bmParent->gltexture; #endif bm->bm_parent=bmParent; bm->bm_data = bmParent->bm_data+(unsigned int)((y*bmParent->bm_rowsize)+x); } void decode_data(ubyte *data, int num_pixels, ubyte *colormap, int *count) { int i; ubyte mapped; for (i = 0; i < num_pixels; i++) { count[*data]++; mapped = *data; *data = colormap[mapped]; data++; } } void gr_set_bitmap_flags (grs_bitmap *pbm, int flags) { pbm->bm_flags = flags; } void gr_set_transparent (grs_bitmap *pbm, int bTransparent) { if (bTransparent) { gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_TRANSPARENT); } else { gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_TRANSPARENT); } } void gr_set_super_transparent (grs_bitmap *pbm, int bTransparent) { if (bTransparent) { gr_set_bitmap_flags (pbm, pbm->bm_flags & ~BM_FLAG_SUPER_TRANSPARENT); } else { gr_set_bitmap_flags (pbm, pbm->bm_flags | BM_FLAG_SUPER_TRANSPARENT); } } void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq ) { int i, r, g, b; for (i=0; i<256; i++ ) { r = *palette++; g = *palette++; b = *palette++; *colormap++ = gr_find_closest_color( r, g, b ); *freq++ = 0; } } void gr_remap_bitmap( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color ) { ubyte colormap[256]; int freq[256]; if (bmp->bm_type != BM_LINEAR) return; //can't do it // This should be build_colormap_asm, but we're not using invert table, so... build_colormap_good( palette, colormap, freq ); if ( (super_transparent_color>=0) && (super_transparent_color<=255)) colormap[super_transparent_color] = 254; if ( (transparent_color>=0) && (transparent_color<=255)) colormap[transparent_color] = TRANSPARENCY_COLOR; decode_data(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq ); if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) ) gr_set_transparent (bmp, 1); if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) ) gr_set_super_transparent (bmp, 0); } void gr_remap_bitmap_good( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color ) { ubyte colormap[256]; int freq[256]; build_colormap_good( palette, colormap, freq ); if ( (super_transparent_color>=0) && (super_transparent_color<=255)) colormap[super_transparent_color] = 254; if ( (transparent_color>=0) && (transparent_color<=255)) colormap[transparent_color] = TRANSPARENCY_COLOR; if (bmp->bm_w == bmp->bm_rowsize) decode_data(bmp->bm_data, bmp->bm_w * bmp->bm_h, colormap, freq ); else { int y; ubyte *p = bmp->bm_data; for (y=0;ybm_h;y++,p+=bmp->bm_rowsize) decode_data(p, bmp->bm_w, colormap, freq ); } if ( (transparent_color>=0) && (transparent_color<=255) && (freq[transparent_color]>0) ) gr_set_transparent (bmp, 1); if ( (super_transparent_color>=0) && (super_transparent_color<=255) && (freq[super_transparent_color]>0) ) gr_set_super_transparent (bmp, 1); } void gr_bitmap_check_transparency( grs_bitmap * bmp ) { int x, y; ubyte * data; data = bmp->bm_data; for (y=0; ybm_h; y++ ) { for (x=0; xbm_w; x++ ) { if (*data++ == TRANSPARENCY_COLOR ) { gr_set_transparent (bmp, 1); return; } } data += bmp->bm_rowsize - bmp->bm_w; } bmp->bm_flags = 0; } dxx-rebirth-0.58.1-d1x/2d/bitmap.h000066400000000000000000000003071217717257200165040ustar00rootroot00000000000000#ifndef _BITMAP_H #define _BITMAP_H void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq ); void decode_data(ubyte *data, int num_pixels, ubyte * colormap, int * count ); #endif dxx-rebirth-0.58.1-d1x/2d/box.c000066400000000000000000000054131217717257200160160ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for drawing boxes. * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" void gr_ubox0(int left,int top,int right,int bot) { int i, d; unsigned char * ptr1; unsigned char * ptr2; ptr1 = DATA + ROWSIZE *top+left; ptr2 = ptr1; d = right - left; for (i=top; i<=bot; i++ ) { ptr2[0] = (unsigned char) COLOR; ptr2[d] = (unsigned char) COLOR; ptr2 += ROWSIZE; } ptr2 = ptr1; d = (bot - top)*ROWSIZE; for (i=1; i<(right-left); i++ ) { ptr2[i+0] = (unsigned char) COLOR; ptr2[i+d] = (unsigned char) COLOR; } } void gr_box0(int left,int top,int right,int bot) { if (top > MAXY ) return; if (bot < MINY ) return; if (left > MAXX ) return; if (right < MINX ) return; if (top < MINY) top = MINY; if (bot > MAXY ) bot = MAXY; if (left < MINX) left = MINX; if (right > MAXX ) right = MAXX; gr_ubox0(left,top,right,bot); } void gr_ubox12(int left,int top,int right,int bot) { #if 0 // the following shifts the box up 1 unit in OpenGL int i; for (i=top; i<=bot; i++ ) { gr_upixel( left, i ); gr_upixel( right, i ); } for (i=left; i<=right; i++ ) { gr_upixel( i, top ); gr_upixel( i, bot ); } #endif gr_uline(i2f(left), i2f(top), i2f(right), i2f(top)); gr_uline(i2f(right), i2f(top), i2f(right), i2f(bot)); gr_uline(i2f(left), i2f(top), i2f(left), i2f(bot)); gr_uline(i2f(left), i2f(bot), i2f(right), i2f(bot)); } void gr_box12(int left,int top,int right,int bot) { if (top > MAXY ) return; if (bot < MINY ) return; if (left > MAXX ) return; if (right < MINX ) return; if (top < MINY) top = MINY; if (bot > MAXY ) bot = MAXY; if (left < MINX) left = MINX; if (right > MAXX ) right = MAXX; gr_ubox12(left, top, right, bot ); } void gr_ubox(int left,int top,int right,int bot) { if (TYPE==BM_LINEAR) gr_ubox0( left, top, right, bot ); else gr_ubox12( left, top, right, bot ); } void gr_box(int left,int top,int right,int bot) { if (TYPE==BM_LINEAR) gr_box0( left, top, right, bot ); else gr_box12( left, top, right, bot ); } dxx-rebirth-0.58.1-d1x/2d/canvas.c000066400000000000000000000065321217717257200165040ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for manipulating grs_canvas's. * */ #include #include #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifdef OGL #include "ogl_init.h" #endif grs_canvas * grd_curcanv; //active canvas grs_screen * grd_curscreen; //active screen grs_canvas *gr_create_canvas(int w, int h) { grs_canvas *new; new = (grs_canvas *)d_malloc( sizeof(grs_canvas) ); gr_init_bitmap_alloc (&new->cv_bitmap, BM_LINEAR, 0, 0, w, h, w); new->cv_color = 0; new->cv_fade_level = GR_FADE_OFF; new->cv_blend_func = GR_BLEND_NORMAL; new->cv_drawmode = 0; new->cv_font = NULL; new->cv_font_fg_color = 0; new->cv_font_bg_color = 0; return new; } grs_canvas *gr_create_sub_canvas(grs_canvas *canv, int x, int y, int w, int h) { grs_canvas *new; new = (grs_canvas *)d_malloc( sizeof(grs_canvas) ); gr_init_sub_bitmap (&new->cv_bitmap, &canv->cv_bitmap, x, y, w, h); new->cv_color = canv->cv_color; new->cv_fade_level = canv->cv_fade_level; new->cv_blend_func = canv->cv_blend_func; new->cv_drawmode = canv->cv_drawmode; new->cv_font = canv->cv_font; new->cv_font_fg_color = canv->cv_font_fg_color; new->cv_font_bg_color = canv->cv_font_bg_color; return new; } void gr_init_canvas(grs_canvas *canv, unsigned char * pixdata, int pixtype, int w, int h) { int wreal; canv->cv_color = 0; canv->cv_fade_level = GR_FADE_OFF; canv->cv_blend_func = GR_BLEND_NORMAL; canv->cv_drawmode = 0; canv->cv_font = NULL; canv->cv_font_fg_color = 0; canv->cv_font_bg_color = 0; wreal = w; gr_init_bitmap (&canv->cv_bitmap, pixtype, 0, 0, w, h, wreal, pixdata); } void gr_init_sub_canvas(grs_canvas *new, grs_canvas *src, int x, int y, int w, int h) { new->cv_color = src->cv_color; new->cv_fade_level = src->cv_fade_level; new->cv_blend_func = src->cv_blend_func; new->cv_drawmode = src->cv_drawmode; new->cv_font = src->cv_font; new->cv_font_fg_color = src->cv_font_fg_color; new->cv_font_bg_color = src->cv_font_bg_color; gr_init_sub_bitmap (&new->cv_bitmap, &src->cv_bitmap, x, y, w, h); } void gr_free_canvas(grs_canvas *canv) { gr_free_bitmap_data(&canv->cv_bitmap); d_free(canv); } void gr_free_sub_canvas(grs_canvas *canv) { d_free(canv); } void gr_set_current_canvas( grs_canvas *canv ) { if (canv==NULL) grd_curcanv = &(grd_curscreen->sc_canvas); else grd_curcanv = canv; } void gr_clear_canvas(int color) { gr_setcolor(color); gr_rect(0,0,GWIDTH-1,GHEIGHT-1); } void gr_setcolor(int color) { grd_curcanv->cv_color=color; } void gr_settransblend(int fade_level, ubyte blend_func) { grd_curcanv->cv_fade_level=fade_level; grd_curcanv->cv_blend_func=blend_func; #ifdef OGL ogl_set_blending(); #endif } dxx-rebirth-0.58.1-d1x/2d/circle.c000066400000000000000000000055371217717257200164760ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/2d/circle.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:00 $ * * . * * $Log: circle.c,v $ * Revision 1.1.1.1 2006/03/17 19:39:00 zicodxx * initial import * * Revision 1.2 1999/10/20 07:34:07 donut * opengl rendered reticle, and better g3_draw_sphere * * Revision 1.1.1.1 1999/06/14 21:57:18 donut * Import of d1x 1.37 source. * * Revision 1.3 1994/11/18 22:51:01 john * Changed a bunch of shorts to ints in calls. * * Revision 1.2 1994/05/12 17:33:18 john * Added circle code. * * Revision 1.1 1994/05/12 17:21:49 john * Initial revision * * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifndef OGL int gr_circle(fix xc1,fix yc1,fix r1) { int p,x, y, xc, yc, r; r = f2i(r1); xc = f2i(xc1); yc = f2i(yc1); p=3-(r*2); x=0; y=r; // Big clip if ( (xc+r) < 0 ) return 1; if ( (xc-r) > GWIDTH ) return 1; if ( (yc+r) < 0 ) return 1; if ( (yc-r) > GHEIGHT ) return 1; while(x (b)) ? (a) : (b)) */ #define IABS(x) (((x) < 0) ? -(x) : (x)) #define EXCHG(a,b) do { \ int __temp__ = (a); \ (a) = (b); \ (b) = __temp__; \ } while(0) // sort two values #define SORT2(a,b) do { \ if((a) > (b)) EXCHG(a,b); \ } while(0) # define SCALE(var,arg,num,den) \ ((var) = ((arg) * (num)) / (den)) # define USCALE(var,arg,num,den) \ ((var) = ((unsigned)(arg) * (unsigned)(num)) / (unsigned)(den)) # define FIXSCALE(var,arg,num,den) ((var) = fixmuldiv((arg),(num),(den))) #define CLIPDOT(xx,yy,WHEN_OUTSIDE,WHEN_CLIPPED) { \ if((xx > XMAX) || (xx < XMIN)) { WHEN_OUTSIDE; } \ if((yy > YMAX) || (yy < YMIN)) { WHEN_OUTSIDE; } \ } #define CLIPHLINE(x1,x2,yy,WHEN_OUTSIDE,WHEN_CLIPPED) { \ if(x1 > x2) EXCHG(x1,x2); \ if((x1 > XMAX) || (x2 < XMIN)) { WHEN_OUTSIDE; } \ if((yy > YMAX) || (yy < YMIN)) { WHEN_OUTSIDE; } \ if(x1 < XMIN) { x1 = XMIN; WHEN_CLIPPED; } \ if(x2 > XMAX) { x2 = XMAX; WHEN_CLIPPED; } \ } #define CLIPVLINE(xx,y1,y2,WHEN_OUTSIDE,WHEN_CLIPPED) { \ if(y1 > y2) EXCHG(y1,y2); \ if((xx > XMAX) || (xx < XMIN)) { WHEN_OUTSIDE; } \ if((y1 > YMAX) || (y2 < YMIN)) { WHEN_OUTSIDE; } \ if(y1 < YMIN) { y1 = YMIN; WHEN_CLIPPED; } \ if(y2 > YMAX) { y2 = YMAX; WHEN_CLIPPED; } \ } #define CLIPBOX(x1,y1,x2,y2,WHEN_OUTSIDE,WHEN_CLIPPED) { \ if(x1 > x2) EXCHG(x1,x2); \ if(y1 > y2) EXCHG(y1,y2); \ if((x1 > XMAX) || (x2 < 0)) { WHEN_OUTSIDE; } \ if((y1 > YMAX) || (y2 < 0)) { WHEN_OUTSIDE; } \ if(x1 < 0) { x1 = 0; WHEN_CLIPPED; } \ if(y1 < 0) { y1 = 0; WHEN_CLIPPED; } \ if(x2 > XMAX) { x2 = XMAX; WHEN_CLIPPED; } \ if(y2 > YMAX) { y2 = YMAX; WHEN_CLIPPED; } \ } #define CLIPLINE(x1,y1,x2,y2,XMIN,YMIN,XMAX,YMAX,WHEN_OUTSIDE,WHEN_CLIPPED,MY_SCALE) do { \ register int temp; \ if(y1 > y2) \ { EXCHG(y1,y2); EXCHG(x1,x2); } \ if((y2 < YMIN) || (y1 > YMAX)) \ { WHEN_OUTSIDE; } \ if(x1 < x2) { \ if((x2 < XMIN) || (x1 > XMAX)) { \ WHEN_OUTSIDE; \ } \ if(x1 < XMIN) { \ MY_SCALE(temp,(y2 - y1),(XMIN - x1),(x2 - x1)); \ if((y1 += temp) > YMAX) { WHEN_OUTSIDE; } \ x1 = XMIN; \ WHEN_CLIPPED; \ } \ if(x2 > XMAX) { \ MY_SCALE(temp,(y2 - y1),(x2 - XMAX),(x2 - x1)); \ if((y2 -= temp) < YMIN) { WHEN_OUTSIDE; } \ x2 = XMAX; \ WHEN_CLIPPED; \ } \ if(y1 < YMIN) { \ MY_SCALE(temp,(x2 - x1),(YMIN - y1),(y2 - y1)); \ x1 += temp; \ y1 = YMIN; \ WHEN_CLIPPED; \ } \ if(y2 > YMAX) { \ MY_SCALE(temp,(x2 - x1),(y2 - YMAX),(y2 - y1)); \ x2 -= temp; \ y2 = YMAX; \ WHEN_CLIPPED; \ } \ } \ else { \ if((x1 < XMIN) || (x2 > XMAX)) { \ WHEN_OUTSIDE; \ } \ if(x1 > XMAX) { \ MY_SCALE(temp,(y2 - y1),(x1 - XMAX),(x1 - x2)); \ if((y1 += temp) > YMAX) { WHEN_OUTSIDE; } \ x1 = XMAX; \ WHEN_CLIPPED; \ } \ if(x2 < XMIN) { \ MY_SCALE(temp,(y2 - y1),(XMIN - x2),(x1 - x2)); \ if((y2 -= temp) < YMIN) { WHEN_OUTSIDE; } \ x2 = XMIN; \ WHEN_CLIPPED; \ } \ if(y1 < YMIN) { \ MY_SCALE(temp,(x1 - x2),(YMIN - y1),(y2 - y1)); \ x1 -= temp; \ y1 = YMIN; \ WHEN_CLIPPED; \ } \ if(y2 > YMAX) { \ MY_SCALE(temp,(x1 - x2),(y2 - YMAX),(y2 - y1)); \ x2 += temp; \ y2 = YMAX; \ WHEN_CLIPPED; \ } \ } \ } while(0) dxx-rebirth-0.58.1-d1x/2d/disc.c000066400000000000000000000014401217717257200161440ustar00rootroot00000000000000/* * * Graphical routines for drawing a disk. * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifndef OGL int gr_disk(fix xc1,fix yc1,fix r1) { int p,x, y, xc, yc, r; r = f2i(r1); xc = f2i(xc1); yc = f2i(yc1); p=3-(r*2); x=0; y=r; // Big clip if ( (xc+r) < 0 ) return 1; if ( (xc-r) > GWIDTH ) return 1; if ( (yc+r) < 0 ) return 1; if ( (yc-r) > GHEIGHT ) return 1; while(x #include #include #include #ifndef macintosh #include #endif #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "dxxerror.h" #include "byteswap.h" #include "bitmap.h" #include "makesig.h" #include "gamefont.h" #include "console.h" #include "config.h" #include "inferno.h" #ifdef OGL #include "ogl_init.h" #endif #define FONTSCALE_X(x) ((float)(x)*(FNTScaleX)) #define FONTSCALE_Y(x) ((float)(x)*(FNTScaleY)) #define MAX_OPEN_FONTS 50 typedef struct openfont { char filename[FILENAME_LEN]; grs_font *ptr; char *dataptr; } openfont; //list of open fonts openfont open_font[MAX_OPEN_FONTS]; #define BITS_TO_BYTES(x) (((x)+7)>>3) int gr_internal_string_clipped(int x, int y, const char *s ); int gr_internal_string_clipped_m(int x, int y, const char *s ); ubyte *find_kern_entry(grs_font *font,ubyte first,ubyte second) { ubyte *p=font->ft_kerndata; while (*p!=255) if (p[0]==first && p[1]==second) return p; else p+=3; return NULL; } //takes the character AFTER being offset into font #define INFONT(_c) ((_c >= 0) && (_c <= grd_curcanv->cv_font->ft_maxchar-grd_curcanv->cv_font->ft_minchar)) //takes the character BEFORE being offset into current font void get_char_width(ubyte c,ubyte c2,int *width,int *spacing) { int letter; letter = c-grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter)) { //not in font, draw as space *width=0; if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) *spacing = FONTSCALE_X(grd_curcanv->cv_font->ft_w)/2; else *spacing = grd_curcanv->cv_font->ft_w; return; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) *width = FONTSCALE_X(grd_curcanv->cv_font->ft_widths[letter]); else *width = grd_curcanv->cv_font->ft_w; *spacing = *width; if (grd_curcanv->cv_font->ft_flags & FT_KERNED) { ubyte *p; if (!(c2==0 || c2=='\n')) { int letter2 = c2-grd_curcanv->cv_font->ft_minchar; if (INFONT(letter2)) { p = find_kern_entry(grd_curcanv->cv_font,(ubyte)letter,letter2); if (p) *spacing = FONTSCALE_X(p[2]); } } } } // Same as above but works with floats, which is better for string-size measurement while being bad for string composition of course void get_char_width_f(ubyte c,ubyte c2,float *width,float *spacing) { int letter; letter = c-grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter)) { //not in font, draw as space *width=0; if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) *spacing = FONTSCALE_X(grd_curcanv->cv_font->ft_w)/2; else *spacing = grd_curcanv->cv_font->ft_w; return; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) *width = FONTSCALE_X(grd_curcanv->cv_font->ft_widths[letter]); else *width = grd_curcanv->cv_font->ft_w; *spacing = *width; if (grd_curcanv->cv_font->ft_flags & FT_KERNED) { ubyte *p; if (!(c2==0 || c2=='\n')) { int letter2 = c2-grd_curcanv->cv_font->ft_minchar; if (INFONT(letter2)) { p = find_kern_entry(grd_curcanv->cv_font,(ubyte)letter,letter2); if (p) *spacing = FONTSCALE_X(p[2]); } } } } int get_centered_x(const char *s) { float w,w2,s2; for (w=0;*s!=0 && *s!='\n';s++) { if (*s<=0x06) { if (*s<=0x03) s++; continue;//skip color codes. } get_char_width_f(s[0],s[1],&w2,&s2); w += s2; } return ((grd_curcanv->cv_bitmap.bm_w - w) / 2); } //hack to allow color codes to be embedded in strings -MPM //note we subtract one from color, since 255 is "transparent" so it'll never be used, and 0 would otherwise end the string. //function must already have orig_color var set (or they could be passed as args...) //perhaps some sort of recursive orig_color type thing would be better, but that would be way too much trouble for little gain int gr_message_color_level=1; #define CHECK_EMBEDDED_COLORS() if ((*text_ptr >= 0x01) && (*text_ptr <= 0x02)) { \ text_ptr++; \ if (*text_ptr){ \ if (gr_message_color_level >= *(text_ptr-1)) \ grd_curcanv->cv_font_fg_color = (unsigned char)*text_ptr; \ text_ptr++; \ } \ } \ else if (*text_ptr == 0x03) \ { \ underline = 1; \ text_ptr++; \ } \ else if ((*text_ptr >= 0x04) && (*text_ptr <= 0x06)){ \ if (gr_message_color_level >= *text_ptr - 3) \ grd_curcanv->cv_font_fg_color=(unsigned char)orig_color; \ text_ptr++; \ } int gr_internal_string0(int x, int y, const char *s ) { unsigned char * fp; const char * text_ptr, * next_row, * text_ptr1; int r, BitMask, i, bits, width, spacing, letter, underline; int skip_lines = 0; unsigned int VideoOffset, VideoOffset1; bits=0; VideoOffset1 = y * ROWSIZE + x; next_row = s; while (next_row != NULL ) { text_ptr1 = next_row; next_row = NULL; if (x==0x8000) { //centered int xx = get_centered_x(text_ptr1); VideoOffset1 = y * ROWSIZE + xx; } for (r=0; rcv_font->ft_h; r++) { text_ptr = text_ptr1; VideoOffset = VideoOffset1; while (*text_ptr) { if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; break; } if (*text_ptr == CC_COLOR) { grd_curcanv->cv_font_fg_color = (unsigned char)*(text_ptr+1); text_ptr += 2; continue; } if (*text_ptr == CC_LSPACING) { skip_lines = *(text_ptr+1) - '0'; text_ptr += 2; continue; } underline = 0; if (*text_ptr == CC_UNDERLINE ) { if ((r==grd_curcanv->cv_font->ft_baseline+2) || (r==grd_curcanv->cv_font->ft_baseline+3)) underline = 1; text_ptr++; } get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); letter = (unsigned char)*text_ptr - grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter)) { //not in font, draw as space VideoOffset += spacing; text_ptr++; continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) fp = grd_curcanv->cv_font->ft_chars[letter]; else fp = grd_curcanv->cv_font->ft_data + letter * BITS_TO_BYTES(width)*grd_curcanv->cv_font->ft_h; if (underline) for (i=0; i< width; i++ ) DATA[VideoOffset++] = (unsigned char) grd_curcanv->cv_font_fg_color; else { fp += BITS_TO_BYTES(width)*r; BitMask = 0; for (i=0; i< width; i++ ) { if (BitMask==0) { bits = *fp++; BitMask = 0x80; } if (bits & BitMask) DATA[VideoOffset++] = (unsigned char) grd_curcanv->cv_font_fg_color; else DATA[VideoOffset++] = (unsigned char) grd_curcanv->cv_font_bg_color; BitMask >>= 1; } } VideoOffset += spacing-width; //for kerning text_ptr++; } VideoOffset1 += ROWSIZE; y++; } y += skip_lines; VideoOffset1 += ROWSIZE * skip_lines; skip_lines = 0; } return 0; } int gr_internal_string0m(int x, int y, const char *s ) { unsigned char * fp; const char * text_ptr, * next_row, * text_ptr1; int r, BitMask, i, bits, width, spacing, letter, underline; int skip_lines = 0; unsigned int VideoOffset, VideoOffset1; int orig_color=grd_curcanv->cv_font_fg_color;//to allow easy reseting to default string color with colored strings -MPM bits = 0; VideoOffset1 = y * ROWSIZE + x; next_row = s; while (next_row != NULL ) { text_ptr1 = next_row; next_row = NULL; if (x==0x8000) { //centered int xx = get_centered_x(text_ptr1); VideoOffset1 = y * ROWSIZE + xx; } for (r=0; rcv_font->ft_h; r++) { text_ptr = text_ptr1; VideoOffset = VideoOffset1; while (*text_ptr) { if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; break; } if (*text_ptr == CC_COLOR) { grd_curcanv->cv_font_fg_color = (unsigned char)*(text_ptr+1); text_ptr += 2; continue; } if (*text_ptr == CC_LSPACING) { skip_lines = *(text_ptr+1) - '0'; text_ptr += 2; continue; } underline = 0; if (*text_ptr == CC_UNDERLINE ) { if ((r==grd_curcanv->cv_font->ft_baseline+2) || (r==grd_curcanv->cv_font->ft_baseline+3)) underline = 1; text_ptr++; } get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); letter = (unsigned char)*text_ptr-grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter) || (unsigned char) *text_ptr <= 0x06) //not in font, draw as space { CHECK_EMBEDDED_COLORS() else{ VideoOffset += spacing; text_ptr++; } continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) fp = grd_curcanv->cv_font->ft_chars[letter]; else fp = grd_curcanv->cv_font->ft_data + letter * BITS_TO_BYTES(width)*grd_curcanv->cv_font->ft_h; if (underline) for (i=0; i< width; i++ ) DATA[VideoOffset++] = (unsigned char) grd_curcanv->cv_font_fg_color; else { fp += BITS_TO_BYTES(width)*r; BitMask = 0; for (i=0; i< width; i++ ) { if (BitMask==0) { bits = *fp++; BitMask = 0x80; } if (bits & BitMask) DATA[VideoOffset++] = (unsigned char) grd_curcanv->cv_font_fg_color; else VideoOffset++; BitMask >>= 1; } } text_ptr++; VideoOffset += spacing-width; } VideoOffset1 += ROWSIZE; y++; } y += skip_lines; VideoOffset1 += ROWSIZE * skip_lines; skip_lines = 0; } return 0; } #ifndef OGL //a bitmap for the character grs_bitmap char_bm = { 0,0,0,0, //x,y,w,h BM_LINEAR, //type BM_FLAG_TRANSPARENT, //flags 0, //rowsize NULL, //data 0, //avg_color 0 //unused }; int gr_internal_color_string(int x, int y, const char *s ) { unsigned char * fp; const char *text_ptr, *next_row, *text_ptr1; int width, spacing,letter; int xx,yy; char_bm.bm_h = grd_curcanv->cv_font->ft_h; //set height for chars of this font next_row = s; yy = y; while (next_row != NULL) { text_ptr1 = next_row; next_row = NULL; text_ptr = text_ptr1; xx = x; if (xx==0x8000) //centered xx = get_centered_x(text_ptr); while (*text_ptr) { if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; yy += grd_curcanv->cv_font->ft_h+FSPACY(1); break; } letter = (unsigned char)*text_ptr - grd_curcanv->cv_font->ft_minchar; get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); if (!INFONT(letter)) { //not in font, draw as space xx += spacing; text_ptr++; continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) fp = grd_curcanv->cv_font->ft_chars[letter]; else fp = grd_curcanv->cv_font->ft_data + letter * BITS_TO_BYTES(width)*grd_curcanv->cv_font->ft_h; gr_init_bitmap (&char_bm, BM_LINEAR, 0, 0, width, grd_curcanv->cv_font->ft_h, width, fp); gr_bitmapm(xx,yy,&char_bm); xx += spacing; text_ptr++; } } return 0; } #else //OGL int get_font_total_width(grs_font * font){ if (font->ft_flags & FT_PROPORTIONAL){ int i,w=0,c=font->ft_minchar; for (i=0;c<=font->ft_maxchar;i++,c++){ if (font->ft_widths[i]<0) Error("heh?\n"); w+=font->ft_widths[i]; } return w; }else{ return font->ft_w*(font->ft_maxchar-font->ft_minchar+1); } } void ogl_font_choose_size(grs_font * font,int gap,int *rw,int *rh){ int nchars = font->ft_maxchar-font->ft_minchar+1; int r,x,y,nc=0,smallest=999999,smallr=-1,tries; int smallprop=10000; int h,w; for (h=32;h<=256;h*=2){ // h=pow2ize(font->ft_h*rows+gap*(rows-1)); if (font->ft_h>h)continue; r=(h/(font->ft_h+gap)); w=pow2ize((get_font_total_width(font)+(nchars-r)*gap)/r); tries=0; do { if (tries) w=pow2ize(w+1); if(tries>3){ break; } nc=0; y=0; while(y+font->ft_h<=h){ x=0; while (xft_flags & FT_PROPORTIONAL){ if (x+font->ft_widths[nc]+gap>w)break; x+=font->ft_widths[nc++]+gap; }else{ if (x+font->ft_w+gap>w)break; x+=font->ft_w+gap; nc++; } } if (nc==nchars) break; y+=font->ft_h+gap; } tries++; }while(nc!=nchars); if (nc!=nchars) continue; if (w*h==smallest){//this gives squarer sizes priority (ie, 128x128 would be better than 512*32) if (w>=h){ if (w/hft_maxchar-font->ft_minchar+1; int i,w,h,tw,th,x,y,curx=0,cury=0; unsigned char *fp; ubyte *data; int gap=1; // x/y offset between the chars so we can filter ogl_font_choose_size(font,gap,&tw,&th); data=d_malloc(tw*th); memset(data, TRANSPARENCY_COLOR, tw * th); // map the whole data with transparency so we won't have borders if using gap gr_init_bitmap(&font->ft_parent_bitmap,BM_LINEAR,0,0,tw,th,tw,data); gr_set_transparent(&font->ft_parent_bitmap, 1); if (!(font->ft_flags & FT_COLOR)) oglflags |= OGL_FLAG_NOCOLOR; ogl_init_texture(font->ft_parent_bitmap.gltexture = ogl_get_free_texture(), tw, th, oglflags); // have to init the gltexture here so the subbitmaps will find it. font->ft_bitmaps=(grs_bitmap*)d_malloc( nchars * sizeof(grs_bitmap)); h=font->ft_h; for(i=0;ift_flags & FT_PROPORTIONAL) w=font->ft_widths[i]; else w=font->ft_w; if (w<1 || w>256) continue; if (curx+w+gap>tw) { cury+=h+gap; curx=0; } if (cury+h>th) Error("font doesn't really fit (%i/%i)?\n",i,nchars); if (font->ft_flags & FT_COLOR) { if (font->ft_flags & FT_PROPORTIONAL) fp = font->ft_chars[i]; else fp = font->ft_data + i * w*h; for (y=0;yft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=fp[x+y*w]; // Let's call this a HACK: // If we filter the fonts, the sliders will be messed up as the border pixels will have an // alpha value while filtering. So the slider bitmaps will not look "connected". // To prevent this, duplicate the first/last pixel-row with a 1-pixel offset. if (gap && i >= 99 && i <= 102) { // See which bitmaps need left/right shifts: // 99 = SLIDER_LEFT - shift RIGHT // 100 = SLIDER_RIGHT - shift LEFT // 101 = SLIDER_MIDDLE - shift LEFT+RIGHT // 102 = SLIDER_MARKER - shift RIGHT // shift left border if (x==0 && i != 99 && i != 102) font->ft_parent_bitmap.bm_data[(curx+x+(cury+y)*tw)-1]=fp[x+y*w]; // shift right border if (x==w-1 && i != 100) font->ft_parent_bitmap.bm_data[(curx+x+(cury+y)*tw)+1]=fp[x+y*w]; } } } } else { int BitMask,bits=0,white=gr_find_closest_color(63,63,63); if (font->ft_flags & FT_PROPORTIONAL) fp = font->ft_chars[i]; else fp = font->ft_data + i * BITS_TO_BYTES(w)*h; for (y=0;yft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=white; else font->ft_parent_bitmap.bm_data[curx+x+(cury+y)*tw]=255; BitMask >>= 1; } } } gr_init_sub_bitmap(&font->ft_bitmaps[i],&font->ft_parent_bitmap,curx,cury,w,h); curx+=w+gap; } ogl_loadbmtexture_f(&font->ft_parent_bitmap, GameCfg.TexFilt); } int ogl_internal_string(int x, int y, const char *s ) { const char * text_ptr, * next_row, * text_ptr1; int width, spacing,letter; int xx,yy; int orig_color=grd_curcanv->cv_font_fg_color;//to allow easy reseting to default string color with colored strings -MPM int underline; next_row = s; yy = y; if (grd_curscreen->sc_canvas.cv_bitmap.bm_type != BM_OGL) Error("carp.\n"); while (next_row != NULL) { text_ptr1 = next_row; next_row = NULL; text_ptr = text_ptr1; xx = x; if (xx==0x8000) //centered xx = get_centered_x(text_ptr); while (*text_ptr) { int ft_w; if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; yy += FONTSCALE_Y(grd_curcanv->cv_font->ft_h)+FSPACY(1); break; } letter = (unsigned char)*text_ptr - grd_curcanv->cv_font->ft_minchar; get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); underline = 0; if (!INFONT(letter) || (unsigned char)*text_ptr <= 0x06) //not in font, draw as space { CHECK_EMBEDDED_COLORS() else{ xx += spacing; text_ptr++; } if (underline) { ubyte save_c = (unsigned char) COLOR; gr_setcolor(grd_curcanv->cv_font_fg_color); gr_rect(xx, yy + grd_curcanv->cv_font->ft_baseline + 2, xx + grd_curcanv->cv_font->ft_w, yy + grd_curcanv->cv_font->ft_baseline + 3); gr_setcolor(save_c); } continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) ft_w = grd_curcanv->cv_font->ft_widths[letter]; else ft_w = grd_curcanv->cv_font->ft_w; if (grd_curcanv->cv_font->ft_flags&FT_COLOR) ogl_ubitmapm_cs(xx,yy,FONTSCALE_X(ft_w),FONTSCALE_Y(grd_curcanv->cv_font->ft_h),&grd_curcanv->cv_font->ft_bitmaps[letter],-1,F1_0); else{ if (grd_curcanv->cv_bitmap.bm_type==BM_OGL) ogl_ubitmapm_cs(xx,yy,ft_w*(FONTSCALE_X(grd_curcanv->cv_font->ft_w)/grd_curcanv->cv_font->ft_w),FONTSCALE_Y(grd_curcanv->cv_font->ft_h),&grd_curcanv->cv_font->ft_bitmaps[letter],grd_curcanv->cv_font_fg_color,F1_0); else Error("ogl_internal_string: non-color string to non-ogl dest\n"); } xx += spacing; text_ptr++; } } return 0; } int gr_internal_color_string(int x, int y, const char *s ){ return ogl_internal_string(x,y,s); } #endif //OGL int gr_string(int x, int y, const char *s ) { int w, h, aw; int clipped=0; Assert(grd_curcanv->cv_font != NULL); if ( x == 0x8000 ) { if ( y<0 ) clipped |= 1; gr_get_string_size(s, &w, &h, &aw ); // for x, since this will be centered, only look at // width. if ( w > grd_curcanv->cv_bitmap.bm_w ) clipped |= 1; if ( (y+h) > grd_curcanv->cv_bitmap.bm_h ) clipped |= 1; if ( (y+h) < 0 ) clipped |= 2; if ( y > grd_curcanv->cv_bitmap.bm_h ) clipped |= 2; } else { if ( (x<0) || (y<0) ) clipped |= 1; gr_get_string_size(s, &w, &h, &aw ); if ( (x+w) > grd_curcanv->cv_bitmap.bm_w ) clipped |= 1; if ( (y+h) > grd_curcanv->cv_bitmap.bm_h ) clipped |= 1; if ( (x+w) < 0 ) clipped |= 2; if ( (y+h) < 0 ) clipped |= 2; if ( x > grd_curcanv->cv_bitmap.bm_w ) clipped |= 2; if ( y > grd_curcanv->cv_bitmap.bm_h ) clipped |= 2; } if ( !clipped ) return gr_ustring(x, y, s ); if ( clipped & 2 ) { // Completely clipped... return 0; } // Partially clipped... #ifdef OGL if (TYPE==BM_OGL) return ogl_internal_string(x,y,s); #endif if (grd_curcanv->cv_font->ft_flags & FT_COLOR) return gr_internal_color_string( x, y, s); if ( grd_curcanv->cv_font_bg_color == -1) return gr_internal_string_clipped_m( x, y, s ); return gr_internal_string_clipped( x, y, s ); } int gr_ustring(int x, int y, const char *s ) { #ifdef OGL if (TYPE==BM_OGL) return ogl_internal_string(x,y,s); #endif if (grd_curcanv->cv_font->ft_flags & FT_COLOR) { return gr_internal_color_string(x,y,s); } else switch( TYPE ) { case BM_LINEAR: if ( grd_curcanv->cv_font_bg_color == -1) return gr_internal_string0m(x,y,s); else return gr_internal_string0(x,y,s); } return 0; } void gr_get_string_size(const char *s, int *string_width, int *string_height, int *average_width ) { int i = 0; float width=0.0,spacing=0.0,longest_width=0.0,string_width_f=0.0,string_height_f=0.0; string_height_f = FONTSCALE_Y(grd_curcanv->cv_font->ft_h); string_width_f = 0; *average_width = grd_curcanv->cv_font->ft_w; if (s != NULL ) { string_width_f = 0; while (*s) { // if (*s == '&') // s++; while (*s == '\n') { s++; string_height_f += FONTSCALE_Y(grd_curcanv->cv_font->ft_h)+FSPACY(1); string_width_f = 0; } if (*s == 0) break; get_char_width_f(s[0],s[1],&width,&spacing); string_width_f += spacing; if (string_width_f > longest_width) longest_width = string_width_f; i++; s++; } } string_width_f = longest_width; *string_width = string_width_f; *string_height = string_height_f; } int gr_uprintf( int x, int y, const char * format, ... ) { char buffer[1000]; va_list args; va_start(args, format ); vsprintf(buffer,format,args); return gr_ustring( x, y, buffer ); } int gr_printf( int x, int y, const char * format, ... ) { char buffer[1000]; va_list args; va_start(args, format ); vsprintf(buffer,format,args); return gr_string( x, y, buffer ); } void gr_close_font( grs_font * font ) { if (font) { int fontnum; char * font_data; //find font in list for (fontnum=0;fontnumft_chars ) d_free( font->ft_chars ); #ifdef OGL if (font->ft_bitmaps) d_free( font->ft_bitmaps ); gr_free_bitmap_data(&font->ft_parent_bitmap); #endif d_free( font ); } } /* * reads a grs_font structure from a PHYSFS_file */ static void grs_font_read(grs_font *gf, PHYSFS_file *fp) { gf->ft_w = PHYSFSX_readShort(fp); gf->ft_h = PHYSFSX_readShort(fp); gf->ft_flags = PHYSFSX_readShort(fp); gf->ft_baseline = PHYSFSX_readShort(fp); gf->ft_minchar = PHYSFSX_readByte(fp); gf->ft_maxchar = PHYSFSX_readByte(fp); gf->ft_bytewidth = PHYSFSX_readShort(fp); gf->ft_data = (ubyte *)((size_t)PHYSFSX_readInt(fp) - GRS_FONT_SIZE); gf->ft_chars = (ubyte **)(size_t)PHYSFSX_readInt(fp); gf->ft_widths = (short *)((size_t)PHYSFSX_readInt(fp) - GRS_FONT_SIZE); gf->ft_kerndata = (ubyte *)((size_t)PHYSFSX_readInt(fp) - GRS_FONT_SIZE); } grs_font * gr_init_font( const char * fontname ) { static int first_time=1; grs_font *font; char *font_data; int i,fontnum; unsigned char * ptr; int nchars; PHYSFS_file *fontfile; char file_id[4]; int datasize; //size up to (but not including) palette if (first_time) { int i; for (i=0;ift_maxchar - font->ft_minchar + 1; if (font->ft_flags & FT_PROPORTIONAL) { font->ft_widths = (short *) &font_data[(size_t)font->ft_widths]; font->ft_data = (unsigned char *) &font_data[(size_t)font->ft_data]; font->ft_chars = (unsigned char **)d_malloc( nchars * sizeof(unsigned char *)); ptr = font->ft_data; for (i=0; i< nchars; i++ ) { font->ft_widths[i] = INTEL_SHORT(font->ft_widths[i]); font->ft_chars[i] = ptr; if (font->ft_flags & FT_COLOR) ptr += font->ft_widths[i] * font->ft_h; else ptr += BITS_TO_BYTES(font->ft_widths[i]) * font->ft_h; } } else { font->ft_data = (unsigned char *) font_data; font->ft_chars = NULL; font->ft_widths = NULL; ptr = font->ft_data + (nchars * font->ft_w * font->ft_h); } if (font->ft_flags & FT_KERNED) font->ft_kerndata = (unsigned char *) &font_data[(size_t)font->ft_kerndata]; if (font->ft_flags & FT_COLOR) { //remap palette ubyte palette[256*3]; ubyte colormap[256]; int freq[256]; PHYSFS_read(fontfile,palette,3,256); //read the palette build_colormap_good( (ubyte *)&palette, colormap, freq ); colormap[TRANSPARENCY_COLOR] = TRANSPARENCY_COLOR; // changed from colormap[255] = 255 to this for macintosh decode_data(font->ft_data, ptr - font->ft_data, colormap, freq ); } PHYSFS_close(fontfile); //set curcanv vars grd_curcanv->cv_font = font; grd_curcanv->cv_font_fg_color = 0; grd_curcanv->cv_font_bg_color = 0; #ifdef OGL ogl_init_font(font); #endif return font; } void gr_set_curfont( grs_font * new ) { grd_curcanv->cv_font = new; } void gr_set_fontcolor( int fg_color, int bg_color ) { grd_curcanv->cv_font_fg_color = fg_color; grd_curcanv->cv_font_bg_color = bg_color; } int gr_internal_string_clipped(int x, int y, const char *s ) { unsigned char * fp; const char * text_ptr, * next_row, * text_ptr1; int r, BitMask, i, bits, width, spacing, letter, underline; int x1 = x, last_x; bits = 0; next_row = s; while (next_row != NULL ) { text_ptr1 = next_row; next_row = NULL; x = x1; if (x==0x8000) //centered x = get_centered_x(text_ptr1); last_x = x; for (r=0; rcv_font->ft_h; r++) { text_ptr = text_ptr1; x = last_x; while (*text_ptr) { if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; break; } if (*text_ptr == CC_COLOR) { grd_curcanv->cv_font_fg_color = (unsigned char)*(text_ptr+1); text_ptr += 2; continue; } if (*text_ptr == CC_LSPACING) { Int3(); // Warning: skip lines not supported for clipped strings. text_ptr += 2; continue; } underline = 0; if (*text_ptr == CC_UNDERLINE ) { if ((r==grd_curcanv->cv_font->ft_baseline+2) || (r==grd_curcanv->cv_font->ft_baseline+3)) underline = 1; text_ptr++; } get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); letter = (unsigned char)*text_ptr-grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter)) { //not in font, draw as space x += spacing; text_ptr++; continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) fp = grd_curcanv->cv_font->ft_chars[letter]; else fp = grd_curcanv->cv_font->ft_data + letter * BITS_TO_BYTES(width)*grd_curcanv->cv_font->ft_h; if (underline) { for (i=0; i< width; i++ ) { gr_setcolor(grd_curcanv->cv_font_fg_color); gr_pixel( x++, y ); } } else { fp += BITS_TO_BYTES(width)*r; BitMask = 0; for (i=0; i< width; i++ ) { if (BitMask==0) { bits = *fp++; BitMask = 0x80; } if (bits & BitMask) gr_setcolor(grd_curcanv->cv_font_fg_color); else gr_setcolor(grd_curcanv->cv_font_bg_color); gr_pixel( x++, y ); BitMask >>= 1; } } x += spacing-width; //for kerning text_ptr++; } y++; } } return 0; } int gr_internal_string_clipped_m(int x, int y, const char *s ) { unsigned char * fp; const char * text_ptr, * next_row, * text_ptr1; int r, BitMask, i, bits, width, spacing, letter, underline; int x1 = x, last_x; bits = 0; next_row = s; while (next_row != NULL ) { text_ptr1 = next_row; next_row = NULL; x = x1; if (x==0x8000) //centered x = get_centered_x(text_ptr1); last_x = x; for (r=0; rcv_font->ft_h; r++) { x = last_x; text_ptr = text_ptr1; while (*text_ptr) { if (*text_ptr == '\n' ) { next_row = &text_ptr[1]; break; } if (*text_ptr == CC_COLOR) { grd_curcanv->cv_font_fg_color = (unsigned char)*(text_ptr+1); text_ptr += 2; continue; } if (*text_ptr == CC_LSPACING) { Int3(); // Warning: skip lines not supported for clipped strings. text_ptr += 2; continue; } underline = 0; if (*text_ptr == CC_UNDERLINE ) { if ((r==grd_curcanv->cv_font->ft_baseline+2) || (r==grd_curcanv->cv_font->ft_baseline+3)) underline = 1; text_ptr++; } get_char_width(text_ptr[0],text_ptr[1],&width,&spacing); letter = (unsigned char)*text_ptr-grd_curcanv->cv_font->ft_minchar; if (!INFONT(letter)) { //not in font, draw as space x += spacing; text_ptr++; continue; } if (grd_curcanv->cv_font->ft_flags & FT_PROPORTIONAL) fp = grd_curcanv->cv_font->ft_chars[letter]; else fp = grd_curcanv->cv_font->ft_data + letter * BITS_TO_BYTES(width)*grd_curcanv->cv_font->ft_h; if (underline) { for (i=0; i< width; i++ ) { gr_setcolor(grd_curcanv->cv_font_fg_color); gr_pixel( x++, y ); } } else { fp += BITS_TO_BYTES(width)*r; BitMask = 0; for (i=0; i< width; i++ ) { if (BitMask==0) { bits = *fp++; BitMask = 0x80; } if (bits & BitMask) { gr_setcolor(grd_curcanv->cv_font_fg_color); gr_pixel( x++, y ); } else { x++; } BitMask >>= 1; } } x += spacing-width; //for kerning text_ptr++; } y++; } } return 0; } dxx-rebirth-0.58.1-d1x/2d/gpixel.c000066400000000000000000000023521217717257200165150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifdef OGL #include "ogl_init.h" #endif unsigned char gr_ugpixel( grs_bitmap * bitmap, int x, int y ) { switch (bitmap->bm_type) { case BM_LINEAR: return bitmap->bm_data[ bitmap->bm_rowsize*y + x ]; #ifdef OGL case BM_OGL: return ogl_ugpixel(bitmap, x, y); #endif } return 0; } unsigned char gr_gpixel( grs_bitmap * bitmap, int x, int y ) { if ((x<0) || (y<0) || (x>=bitmap->bm_w) || (y>=bitmap->bm_h)) return 0; return gr_ugpixel(bitmap, x, y); } dxx-rebirth-0.58.1-d1x/2d/line.c000066400000000000000000000147741217717257200161670ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for drawing lines. * */ #include #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "fix.h" #include "clip.h" #ifdef OGL #include "ogl_init.h" #endif /* Symmetric Double Step Line Algorithm by Brian Wyvill from "Graphics Gems", Academic Press, 1990 */ /* non-zero flag indicates the pixels needing EXCHG back. */ void plot(int x,int y,int flag) { if (flag) gr_upixel(y, x); else gr_upixel(x, y); } int gr_hline(int x1, int x2, int y) { int i; if (x1 > x2) EXCHG(x1,x2); for (i=x1; i<=x2; i++ ) gr_upixel( i, y ); return 0; } int gr_vline(int y1, int y2, int x) { int i; if (y1 > y2) EXCHG(y1,y2); for (i=y1; i<=y2; i++ ) gr_upixel( x, i ); return 0; } void gr_universal_uline(int a1, int b1, int a2, int b2) { int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left; int x1, y1; int sign_x = 1, sign_y = 1, step, reverse, i; if (a1==a2) { gr_vline(b1,b2,a1); return; } if (b1==b2) { gr_hline(a1,a2,b1); return; } dx = a2 - a1; dy = b2 - b1; if (dx < 0) { sign_x = -1; dx *= -1; } if (dy < 0) { sign_y = -1; dy *= -1; } /* decide increment sign by the slope sign */ if (sign_x == sign_y) step = 1; else step = -1; if (dy > dx) { /* chooses axis of greatest movement (make * dx) */ EXCHG(a1, b1); EXCHG(a2, b2); EXCHG(dx, dy); reverse = 1; } else reverse = 0; /* note error check for dx==0 should be included here */ if (a1 > a2) { /* start from the smaller coordinate */ x = a2; y = b2; x1 = a1; y1 = b1; } else { x = a1; y = b1; x1 = a2; y1 = b2; } /* Note dx=n implies 0 - n or (dx+1) pixels to be set */ /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */ /* In fact (dx-1)/4 as 2 pixels are already plottted */ xend = (dx - 1) / 4; pixels_left = (dx - 1) % 4; /* number of pixels left over at the * end */ plot(x, y, reverse); plot(x1, y1, reverse); /* plot first two points */ incr2 = 4 * dy - 2 * dx; if (incr2 < 0) { /* slope less than 1/2 */ c = 2 * dy; incr1 = 2 * c; D = incr1 - dx; for (i = 0; i < xend; i++) { /* plotting loop */ ++x; --x1; if (D < 0) { /* pattern 1 forwards */ plot(x, y, reverse); plot(++x, y, reverse); /* pattern 1 backwards */ plot(x1, y1, reverse); plot(--x1, y1, reverse); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ plot(x, y, reverse); plot(++x, y += step, reverse); /* pattern 2 backwards */ plot(x1, y1, reverse); plot(--x1, y1 -= step, reverse); } else { /* pattern 3 forwards */ plot(x, y += step, reverse); plot(++x, y, reverse); /* pattern 3 backwards */ plot(x1, y1 -= step, reverse); plot(--x1, y1, reverse); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D < 0) { plot(++x, y, reverse); /* pattern 1 */ if (pixels_left > 1) plot(++x, y, reverse); if (pixels_left > 2) plot(--x1, y1, reverse); } else { if (D < c) { plot(++x, y, reverse); /* pattern 2 */ if (pixels_left > 1) plot(++x, y += step, reverse); if (pixels_left > 2) plot(--x1, y1, reverse); } else { /* pattern 3 */ plot(++x, y += step, reverse); if (pixels_left > 1) plot(++x, y, reverse); if (pixels_left > 2) plot(--x1, y1 -= step, reverse); } } } /* end if pixels_left */ } /* end slope < 1/2 */ else { /* slope greater than 1/2 */ c = 2 * (dy - dx); incr1 = 2 * c; D = incr1 + dx; for (i = 0; i < xend; i++) { ++x; --x1; if (D > 0) { /* pattern 4 forwards */ plot(x, y += step, reverse); plot(++x, y += step, reverse); /* pattern 4 backwards */ plot(x1, y1 -= step, reverse); plot(--x1, y1 -= step, reverse); D += incr1; } else { if (D < c) { /* pattern 2 forwards */ plot(x, y, reverse); plot(++x, y += step, reverse); /* pattern 2 backwards */ plot(x1, y1, reverse); plot(--x1, y1 -= step, reverse); } else { /* pattern 3 forwards */ plot(x, y += step, reverse); plot(++x, y, reverse); /* pattern 3 backwards */ plot(x1, y1 -= step, reverse); plot(--x1, y1, reverse); } D += incr2; } } /* end for */ /* plot last pattern */ if (pixels_left) { if (D > 0) { plot(++x, y += step, reverse); /* pattern 4 */ if (pixels_left > 1) plot(++x, y += step, reverse); if (pixels_left > 2) plot(--x1, y1 -= step, reverse); } else { if (D < c) { plot(++x, y, reverse); /* pattern 2 */ if (pixels_left > 1) plot(++x, y += step, reverse); if (pixels_left > 2) plot(--x1, y1, reverse); } else { /* pattern 3 */ plot(++x, y += step, reverse); if (pixels_left > 1) plot(++x, y, reverse); if (pixels_left > 2) { if (D > c) /* step 3 */ plot(--x1, y1 -= step, reverse); else /* step 2 */ plot(--x1, y1, reverse); } } } } } } //unclipped version just calls clipping version for now int gr_uline(fix _a1, fix _b1, fix _a2, fix _b2) { int a1,b1,a2,b2; a1 = f2i(_a1); b1 = f2i(_b1); a2 = f2i(_a2); b2 = f2i(_b2); switch(TYPE) { #ifdef OGL case BM_OGL: ogl_ulinec(a1,b1,a2,b2,COLOR); return 0; #endif case BM_LINEAR: gr_universal_uline( a1,b1,a2,b2); return 0; } return 2; } // Returns 0 if drawn with no clipping, 1 if drawn but clipped, and // 2 if not drawn at all. int gr_line(fix a1, fix b1, fix a2, fix b2) { int x1, y1, x2, y2; int clipped=0; x1 = i2f(MINX); y1 = i2f(MINY); x2 = i2f(MAXX); y2 = i2f(MAXY); CLIPLINE(a1,b1,a2,b2,x1,y1,x2,y2,return 2,clipped=1, FIXSCALE ); gr_uline( a1, b1, a2, b2 ); return clipped; } dxx-rebirth-0.58.1-d1x/2d/palette.c000066400000000000000000000123371217717257200166670ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for setting the palette * */ #include #include #include "physfsx.h" #include "pstypes.h" #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "dxxerror.h" #include "fix.h" extern int gr_installed; ubyte gr_palette[256*3]; ubyte gr_current_pal[256*3]; ubyte gr_fade_table[256*34]; ubyte gr_palette_gamma = 0; int gr_palette_gamma_param = 0; extern void gr_palette_load( ubyte * pal ); void gr_palette_set_gamma( int gamma ) { if ( gamma < 0 ) gamma = 0; if ( gamma > 16 ) gamma = 16; //was 8 if (gr_palette_gamma_param != gamma ) { gr_palette_gamma_param = gamma; gr_palette_gamma = gamma; gr_palette_load( gr_palette ); } } int gr_palette_get_gamma() { return gr_palette_gamma_param; } void gr_use_palette_table( char * filename ) { PHYSFS_file *fp; int i,fsize; fp = PHYSFSX_openReadBuffered( filename ); if ( fp==NULL) Error("Can't open palette file <%s>",filename); fsize = PHYSFS_fileLength( fp ); Assert( fsize == 9472 ); (void)fsize; PHYSFS_read( fp, gr_palette, 256*3, 1 ); PHYSFS_read( fp, gr_fade_table, 256*34, 1 ); PHYSFS_close(fp); // This is the TRANSPARENCY COLOR for (i=0; i> 15; Computed_colors[add_index].r = r; Computed_colors[add_index].g = g; Computed_colors[add_index].b = b; Computed_colors[add_index].color_num = color_num; } void init_computed_colors(void) { int i; for (i=0; i 4) { color_record trec; trec = Computed_colors[i-1]; Computed_colors[i-1] = Computed_colors[i]; Computed_colors[i] = trec; return Computed_colors[i-1].color_num; } return Computed_colors[i].color_num; } // r &= 63; // g &= 63; // b &= 63; best_value = SQUARE(r-gr_palette[0])+SQUARE(g-gr_palette[1])+SQUARE(b-gr_palette[2]); best_index = 0; if (best_value==0) { add_computed_color(r, g, b, best_index); return best_index; } j=0; // only go to 255, 'cause we dont want to check the transparent color. for (i=1; i<254; i++ ) { j += 3; value = SQUARE(r-gr_palette[j])+SQUARE(g-gr_palette[j+1])+SQUARE(b-gr_palette[j+2]); if ( value < best_value ) { if (value==0) { add_computed_color(r, g, b, i); return i; } best_value = value; best_index = i; } } add_computed_color(r, g, b, best_index); return best_index; } int gr_find_closest_color_15bpp( int rgb ) { return gr_find_closest_color( ((rgb>>10)&31)*2, ((rgb>>5)&31)*2, (rgb&31)*2 ); } int gr_find_closest_color_current( int r, int g, int b ) { int i, j; int best_value, best_index, value; // r &= 63; // g &= 63; // b &= 63; best_value = SQUARE(r-gr_current_pal[0])+SQUARE(g-gr_current_pal[1])+SQUARE(b-gr_current_pal[2]); best_index = 0; if (best_value==0) return best_index; j=0; // only go to 255, 'cause we dont want to check the transparent color. for (i=1; i<254; i++ ) { j += 3; value = SQUARE(r-gr_current_pal[j])+SQUARE(g-gr_current_pal[j+1])+SQUARE(b-gr_current_pal[j+2]); if ( value < best_value ) { if (value==0) return i; best_value = value; best_index = i; } } return best_index; } void gr_make_cthru_table(ubyte * table, ubyte r, ubyte g, ubyte b ) { int i; ubyte r1, g1, b1; for (i=0; i<256; i++ ) { r1 = gr_palette[i*3+0] + r; if ( r1 > 63 ) r1 = 63; g1 = gr_palette[i*3+1] + g; if ( g1 > 63 ) g1 = 63; b1 = gr_palette[i*3+2] + b; if ( b1 > 63 ) b1 = 63; table[i] = gr_find_closest_color( r1, g1, b1 ); } } dxx-rebirth-0.58.1-d1x/2d/pcx.c000066400000000000000000000241731217717257200160240ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to read/write pcx images. * */ #include #include #include #include "gr.h" #include "grdef.h" #include "u_mem.h" #include "pcx.h" #include "physfsx.h" int pcx_encode_byte(ubyte byt, ubyte cnt, PHYSFS_file *fid); int pcx_encode_line(ubyte *inBuff, int inLen, PHYSFS_file *fp); /* PCX Header data type */ typedef struct { ubyte Manufacturer; ubyte Version; ubyte Encoding; ubyte BitsPerPixel; short Xmin; short Ymin; short Xmax; short Ymax; short Hdpi; short Vdpi; ubyte ColorMap[16][3]; ubyte Reserved; ubyte Nplanes; short BytesPerLine; ubyte filler[60]; } __pack__ PCXHeader; #define PCXHEADER_SIZE 128 /* * reads n PCXHeader structs from a PHYSFS_file */ int PCXHeader_read_n(PCXHeader *ph, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) { ph->Manufacturer = PHYSFSX_readByte(fp); ph->Version = PHYSFSX_readByte(fp); ph->Encoding = PHYSFSX_readByte(fp); ph->BitsPerPixel = PHYSFSX_readByte(fp); ph->Xmin = PHYSFSX_readShort(fp); ph->Ymin = PHYSFSX_readShort(fp); ph->Xmax = PHYSFSX_readShort(fp); ph->Ymax = PHYSFSX_readShort(fp); ph->Hdpi = PHYSFSX_readShort(fp); ph->Vdpi = PHYSFSX_readShort(fp); PHYSFS_read( fp, &ph->ColorMap, 16*3, 1 ); ph->Reserved = PHYSFSX_readByte(fp); ph->Nplanes = PHYSFSX_readByte(fp); ph->BytesPerLine = PHYSFSX_readShort(fp); PHYSFS_read(fp, &ph->filler, 60, 1); } return i; } int bald_guy_load( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette ) { PCXHeader header; PHYSFS_file * PCXfile; int i, count, fsize; ubyte data, c, xor_value, *pixdata; ubyte *bguy_data, *bguy_data1, *p; unsigned int row, xsize; unsigned int col, ysize; PCXfile = PHYSFSX_openReadBuffered( filename ); if ( !PCXfile ) return PCX_ERROR_OPENING; PHYSFSX_fseek(PCXfile, -1, SEEK_END); fsize = PHYSFS_tell(PCXfile); PHYSFS_read(PCXfile, &xor_value, 1, 1); xor_value--; PHYSFSX_fseek(PCXfile, 0, SEEK_SET); bguy_data = (ubyte *)d_malloc(fsize); bguy_data1 = (ubyte *)d_malloc(fsize); PHYSFS_read(PCXfile, bguy_data1, 1, fsize); for (i = 0; i < fsize; i++) { c = bguy_data1[fsize - i - 1] ^ xor_value; bguy_data[i] = c; xor_value--; } PHYSFS_close(PCXfile); d_free(bguy_data1); p = bguy_data; memcpy( &header, p, sizeof(PCXHeader) ); p += sizeof(PCXHeader); // Is it a 256 color PCX file? if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) { d_free(bguy_data); return PCX_ERROR_WRONG_VERSION; } header.Xmin= INTEL_SHORT(header.Xmin); header.Xmax = INTEL_SHORT(header.Xmax); header.Ymin = INTEL_SHORT(header.Ymin); header.Ymax = INTEL_SHORT(header.Ymax); // Find the size of the image xsize = header.Xmax - header.Xmin + 1; ysize = header.Ymax - header.Ymin + 1; if ( bmp->bm_data == NULL ) { memset( bmp, 0, sizeof( grs_bitmap ) ); bmp->bm_data = d_malloc( xsize * ysize ); if ( bmp->bm_data == NULL ) { d_free(bguy_data); return PCX_ERROR_MEMORY; } bmp->bm_w = bmp->bm_rowsize = xsize; bmp->bm_h = ysize; bmp->bm_type = bitmap_type; } for (row=0; row< ysize ; row++) { for (row=0; row< ysize ; row++) { pixdata = &bmp->bm_data[bmp->bm_rowsize*row]; for (col=0; col< xsize ; ) { data = *p; p++; if ((data & 0xC0) == 0xC0) { count = data & 0x3F; data = *p; p++; memset( pixdata, data, count ); pixdata += count; col += count; } else { *pixdata++ = data; col++; } } } } // Read the extended palette at the end of PCX file // Read in a character which should be 12 to be extended palette file p++; if (palette != NULL) { for (i = 0; i < 768; i++) { palette[i] = *p; palette[i] >>= 2; p++; } } d_free(bguy_data); return PCX_ERROR_NONE; } int pcx_read_bitmap( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette ) { PCXHeader header; PHYSFS_file * PCXfile; int i, row, col, count, xsize, ysize; ubyte data, *pixdata; PCXfile = PHYSFSX_openReadBuffered( filename ); if ( !PCXfile ) return PCX_ERROR_OPENING; // read 128 char PCX header if (PCXHeader_read_n( &header, 1, PCXfile )!=1) { PHYSFS_close( PCXfile ); return PCX_ERROR_NO_HEADER; } // Is it a 256 color PCX file? if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) { PHYSFS_close( PCXfile ); return PCX_ERROR_WRONG_VERSION; } // Find the size of the image xsize = header.Xmax - header.Xmin + 1; ysize = header.Ymax - header.Ymin + 1; if ( bitmap_type == BM_LINEAR ) { if ( bmp->bm_data == NULL ) { gr_init_bitmap_alloc (bmp, bitmap_type, 0, 0, xsize, ysize, xsize); } } if ( bmp->bm_type == BM_LINEAR ) { for (row=0; row< ysize ; row++) { pixdata = &bmp->bm_data[bmp->bm_rowsize*row]; for (col=0; col< xsize ; ) { if (PHYSFS_read( PCXfile, &data, 1, 1 )!=1 ) { PHYSFS_close( PCXfile ); return PCX_ERROR_READING; } if ((data & 0xC0) == 0xC0) { count = data & 0x3F; if (PHYSFS_read( PCXfile, &data, 1, 1 )!=1 ) { PHYSFS_close( PCXfile ); return PCX_ERROR_READING; } memset( pixdata, data, count ); pixdata += count; col += count; } else { *pixdata++ = data; col++; } } } } else { for (row=0; row< ysize ; row++) { for (col=0; col< xsize ; ) { if (PHYSFS_read( PCXfile, &data, 1, 1 )!=1 ) { PHYSFS_close( PCXfile ); return PCX_ERROR_READING; } if ((data & 0xC0) == 0xC0) { count = data & 0x3F; if (PHYSFS_read( PCXfile, &data, 1, 1 )!=1 ) { PHYSFS_close( PCXfile ); return PCX_ERROR_READING; } for (i=0;i>= 2; } } else { PHYSFS_close( PCXfile ); return PCX_ERROR_NO_PALETTE; } } PHYSFS_close(PCXfile); return PCX_ERROR_NONE; } int pcx_write_bitmap( char * filename, grs_bitmap * bmp, ubyte * palette ) { int retval; int i; ubyte data; PCXHeader header; PHYSFS_file *PCXfile; memset( &header, 0, PCXHEADER_SIZE ); header.Manufacturer = 10; header.Encoding = 1; header.Nplanes = 1; header.BitsPerPixel = 8; header.Version = 5; header.Xmax = bmp->bm_w-1; header.Ymax = bmp->bm_h-1; header.BytesPerLine = bmp->bm_w; PCXfile = PHYSFSX_openWriteBuffered(filename); if ( !PCXfile ) return PCX_ERROR_OPENING; if (PHYSFS_write(PCXfile, &header, PCXHEADER_SIZE, 1) != 1) { PHYSFS_close(PCXfile); return PCX_ERROR_WRITING; } for (i=0; ibm_h; i++ ) { if (!pcx_encode_line( &bmp->bm_data[bmp->bm_rowsize*i], bmp->bm_w, PCXfile )) { PHYSFS_close(PCXfile); return PCX_ERROR_WRITING; } } // Mark an extended palette data = 12; if (PHYSFS_write(PCXfile, &data, 1, 1) != 1) { PHYSFS_close(PCXfile); return PCX_ERROR_WRITING; } // Write the extended palette for (i=0; i<768; i++ ) palette[i] <<= 2; retval = PHYSFS_write(PCXfile, palette, 768, 1); for (i=0; i<768; i++ ) palette[i] >>= 2; if (retval !=1) { PHYSFS_close(PCXfile); return PCX_ERROR_WRITING; } PHYSFS_close(PCXfile); return PCX_ERROR_NONE; } // returns number of bytes written into outBuff, 0 if failed int pcx_encode_line(ubyte *inBuff, int inLen, PHYSFS_file *fp) { ubyte this, last; int srcIndex, i; register int total; register ubyte runCount; // max single runlength is 63 total = 0; last = *(inBuff); runCount = 1; for (srcIndex = 1; srcIndex < inLen; srcIndex++) { this = *(++inBuff); if (this == last) { runCount++; // it encodes if (runCount == 63) { if (!(i=pcx_encode_byte(last, runCount, fp))) return(0); total += i; runCount = 0; } } else { // this != last if (runCount) { if (!(i=pcx_encode_byte(last, runCount, fp))) return(0); total += i; } last = this; runCount = 1; } } if (runCount) { // finish up if (!(i=pcx_encode_byte(last, runCount, fp))) return 0; return total + i; } return total; } // subroutine for writing an encoded byte pair // returns count of bytes written, 0 if error int pcx_encode_byte(ubyte byt, ubyte cnt, PHYSFS_file *fid) { if (cnt) { if ( (cnt==1) && (0xc0 != (0xc0 & byt)) ) { if(EOF == PHYSFSX_putc(fid, (int)byt)) return 0; // disk write error (probably full) return 1; } else { if(EOF == PHYSFSX_putc(fid, (int)0xC0 | cnt)) return 0; // disk write error if(EOF == PHYSFSX_putc(fid, (int)byt)) return 0; // disk write error return 2; } } return 0; } //text for error messges static const char pcx_error_messages[] = { "No error.\0" "Error opening file.\0" "Couldn't read PCX header.\0" "Unsupported PCX version.\0" "Error reading data.\0" "Couldn't find palette information.\0" "Error writing data.\0" }; //function to return pointer to error message const char *pcx_errormsg(int error_number) { const char *p = pcx_error_messages; while (error_number--) { if (!p) return NULL; p += strlen(p)+1; } return p; } dxx-rebirth-0.58.1-d1x/2d/pixel.c000066400000000000000000000031371217717257200163500ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for setting a pixel. * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifdef OGL #include "ogl_init.h" #endif void gr_upixel( int x, int y ) { switch (TYPE) { #ifdef OGL case BM_OGL: ogl_upixelc(x,y,COLOR); return; #endif case BM_LINEAR: DATA[ ROWSIZE*y+x ] = COLOR; return; } } void gr_pixel( int x, int y ) { if ((x<0) || (y<0) || (x>=GWIDTH) || (y>=GHEIGHT)) return; gr_upixel (x, y); } static inline void gr_bm_upixel( grs_bitmap * bm, int x, int y, unsigned char color ) { switch (bm->bm_type) { #ifdef OGL case BM_OGL: ogl_upixelc(bm->bm_x+x,bm->bm_y+y,color); return; #endif case BM_LINEAR: bm->bm_data[ bm->bm_rowsize*y+x ] = color; return; } } void gr_bm_pixel( grs_bitmap * bm, int x, int y, unsigned char color ) { if ((x<0) || (y<0) || (x>=bm->bm_w) || (y>=bm->bm_h)) return; gr_bm_upixel (bm, x, y, color); } dxx-rebirth-0.58.1-d1x/2d/poly.c000066400000000000000000000151611217717257200162120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/2d/poly.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:00 $ * * Graphical routines for drawing polygons. * * $Log: poly.c,v $ * Revision 1.1.1.1 2006/03/17 19:39:00 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 21:57:32 donut * Import of d1x 1.37 source. * * Revision 1.5 1994/11/13 13:03:43 john * Added paged out bit in bitmap structure. Commented out the * poly code that is never used. * * Revision 1.4 1994/03/14 16:56:13 john * Changed grs_bitmap structure to include bm_flags. * * Revision 1.3 1993/10/15 16:23:14 john * y * * Revision 1.2 1993/10/08 14:30:39 john * *** empty log message *** * * Revision 1.1 1993/09/08 11:44:13 john * Initial revision * * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" //#define USE_POLY_CODE 1 #define MAX_SCAN_LINES 1200 #ifdef USE_POLY_CODE int y_edge_list[MAX_SCAN_LINES]; void gr_upoly(int nverts, int *vert ) { int temp; int startx, stopx; // X coordinates of both ends of current edge. int firstx, firsty; // Saved copy of the first vertex to connect later. int dx_dy; // Slope of current edge. int miny, maxy; int starty, stopy; // Y coordinates of both ends of current edge. int x1, x2, i; // Find the min and max rows to clear out the minimun y_edge_list. // (Is it worth it?) maxy = vert[1]; miny = vert[1]; for (i=3; i<(nverts*2); i+=2 ) { if (vert[i]>maxy) maxy=vert[i]; if (vert[i]>= 16; miny--; // -1 to be safe maxy >>= 16; maxy++; // +1 to be safe // Clear only the part of the y_edge_list that w will be using if (miny < 0) miny = 0; if (maxy > MAX_SCAN_LINES) maxy = MAX_SCAN_LINES; for (i=miny; i> 16; do { nverts--; // Get the beginning coordinates of the current edge. startx = vert[0]; starty = vert[1] >> 16; // Get the ending coordinates of the current edge. if (nverts > 0 ) { stopx = vert[2]; stopy = vert[3] >> 16; vert += 2; } else { stopx = firstx; // Last edge, uses first vertex as endpoint stopy = firsty; } if (stopy < starty ) { temp = stopy; stopy = starty; starty = temp; temp = stopx; stopx = startx; startx = temp; } if (stopy == starty ) { // Draw a edge going horizontally across screen x1 = startx>>16; x2 = stopx>>16; if (x2 > x1 ) //gr_uscanline( x1, x2-1, stopy ); gr_uscanline( x1, x2, stopy ); else //gr_uscanline( x2, x1-1, stopy ); gr_uscanline( x2, x1, stopy ); } else { dx_dy = (stopx - startx) / (stopy - starty); for (; starty < stopy; starty++ ) { if (y_edge_list[starty]==-1) y_edge_list[starty] = startx; else { x1 = y_edge_list[starty]>>16; x2 = startx>>16; if (x2 > x1 ) //gr_uscanline( x1, x2-1, starty ); gr_uscanline( x1, x2, starty ); else //gr_uscanline( x2, x1-1, starty ); gr_uscanline( x2, x1, starty ); } startx += dx_dy; } } } while (nverts > 0); } void gr_poly(int nverts, int *vert ) { int temp; int startx, stopx; // X coordinates of both ends of current edge. int firstx, firsty; // Saved copy of the first vertex to connect later. int dx_dy; // Slope of current edge. int miny, maxy; int starty, stopy; // Y coordinates of both ends of current edge. int x1, x2, i, j; // Find the min and max rows to clear out the minimun y_edge_list. // (Is it worth it?) maxy = vert[1]; miny = vert[1]; j = 0; for (i=3; i<(nverts*2); i+=2 ) { if (vert[i]>maxy) { if ((maxy=vert[i]) > MAXY) j++; //if (j>1) break; } if (vert[i]1) break; } } miny >>= 16; miny--; // -1 to be safe maxy >>= 16; maxy++; // +1 to be safe if (miny < MINY) miny = MINY; if (maxy > MAXY) maxy = MAXY+1; // Clear only the part of the y_edge_list that w will be using for (i=miny; i> 16; do { nverts--; // Get the beginning coordinates of the current edge. startx = vert[0]; starty = vert[1] >> 16; // Get the ending coordinates of the current edge. if (nverts > 0 ) { stopx = vert[2]; stopy = vert[3] >> 16; vert += 2; } else { stopx = firstx; // Last edge, uses first vertex as endpoint stopy = firsty; } if (stopy < starty ) { temp = stopy; stopy = starty; starty = temp; temp = stopx; stopx = startx; startx = temp; } if (stopy == starty ) { // Draw a edge going horizontally across screen if ((stopy >= MINY) && (stopy <=MAXY )) { x1 = startx>>16; x2 = stopx>>16; if (x1 > x2 ) { temp = x2; x2 = x1; x1 = temp; } if ((x1 <= MAXX ) && (x2 >= MINX)) { if (x1 < MINX ) x1 = MINX; if (x2 > MAXX ) x2 = MAXX+1; //gr_uscanline( x1, x2-1, stopy ); gr_scanline( x1, x2, stopy ); } } } else { dx_dy = (stopx - startx) / (stopy - starty); if (starty < MINY ) { startx = dx_dy*(MINY-starty)+startx; starty = MINY; } if (stopy > MAXY ) { stopx = dx_dy*(MAXY-starty)+startx; stopy = MAXY+1; } for (; starty < stopy; starty++ ) { if (y_edge_list[starty]==-1) y_edge_list[starty] = startx; else { x1 = y_edge_list[starty]>>16; x2 = startx>>16; if (x1 > x2 ) { temp = x2; x2 = x1; x1 = temp; } if ((x1 <= MAXX ) && (x2 >= MINX)) { if (x1 < MINX ) x1 = MINX; if (x2 > MAXX ) x2 = MAXX+1; //gr_uscanline( x1, x2-1, starty ); gr_scanline( x1, x2, starty ); } } startx += dx_dy; } } } while (nverts > 0); } #endif dxx-rebirth-0.58.1-d1x/2d/rect.c000066400000000000000000000024471217717257200161670ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Graphical routines for drawing rectangles. * */ #include "u_mem.h" #include "gr.h" #include "grdef.h" #ifdef OGL #include "ogl_init.h" #endif void gr_urect(int left,int top,int right,int bot) { #ifdef OGL if (TYPE == BM_OGL) { ogl_urect(left,top,right,bot); return; } #else int i; for ( i=top; i<=bot; i++ ) gr_uscanline( left, right, i ); #endif } void gr_rect(int left,int top,int right,int bot) { int i; #ifdef OGL if (TYPE == BM_OGL) { ogl_urect(left,top,right,bot); return; } #endif for ( i=top; i<=bot; i++ ) gr_scanline( left, right, i ); } dxx-rebirth-0.58.1-d1x/2d/rle.c000066400000000000000000000344241217717257200160140ustar00rootroot00000000000000/*THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to do run length encoding/decoding * on bitmaps. * */ #include #include #include #include "pstypes.h" #include "u_mem.h" #include "gr.h" #include "grdef.h" #include "dxxerror.h" #include "rle.h" #include "byteswap.h" #define RLE_CODE 0xE0 #define NOT_RLE_CODE 31 #define IS_RLE_CODE(x) (((x) & RLE_CODE) == RLE_CODE) #define rle_stosb(_dest, _len, _color) memset(_dest,_color,_len) void gr_rle_decode( ubyte * src, ubyte * dest ) { int i; ubyte data, count = 0; while(1) { data = *src++; if ( ! IS_RLE_CODE(data) ) { *dest++ = data; } else { count = data & NOT_RLE_CODE; if (count == 0) return; data = *src++; for (i = 0; i < count; i++) *dest++ = data; } } } // Given pointer to start of one scanline of rle data, uncompress it to // dest, from source pixels x1 to x2. void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 ) { int i = 0; ubyte count; ubyte color=0; if ( x2 < x1 ) return; count = 0; while ( i < x1 ) { color = *src++; if ( color == RLE_CODE ) return; if ( IS_RLE_CODE(color) ) { count = color & (~RLE_CODE); color = *src++; } else { // unique count = 1; } i += count; } count = i - x1; i = x1; // we know have '*count' pixels of 'color'. if ( x1+count > x2 ) { count = x2-x1+1; if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color ); return; } if ( color != TRANSPARENCY_COLOR ) rle_stosb( dest, count, color ); dest += count; i += count; while( i <= x2 ) { color = *src++; if ( color == RLE_CODE ) return; if ( IS_RLE_CODE(color) ) { count = color & (~RLE_CODE); color = *src++; } else { // unique count = 1; } // we know have '*count' pixels of 'color'. if ( i+count <= x2 ) { if ( color != 255 )rle_stosb( dest, count, color ); i += count; dest += count; } else { count = x2-i+1; if ( color != 255 )rle_stosb( dest, count, color ); i += count; dest += count; } } } void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 ) { int i = 0; ubyte count; ubyte color=0; if ( x2 < x1 ) return; count = 0; while ( i < x1 ) { color = *src++; if ( color == RLE_CODE ) return; if ( IS_RLE_CODE(color) ) { count = color & (~RLE_CODE); color = *src++; } else { // unique count = 1; } i += count; } count = i - x1; i = x1; // we know have '*count' pixels of 'color'. if ( x1+count > x2 ) { count = x2-x1+1; rle_stosb( dest, count, color ); return; } rle_stosb( dest, count, color ); dest += count; i += count; while( i <= x2 ) { color = *src++; if ( color == RLE_CODE ) return; if ( IS_RLE_CODE(color) ) { count = color & (~RLE_CODE); color = *src++; } else { // unique count = 1; } // we know have '*count' pixels of 'color'. if ( i+count <= x2 ) { rle_stosb( dest, count, color ); i += count; dest += count; } else { count = x2-i+1; rle_stosb( dest, count, color ); i += count; dest += count; } } } int gr_rle_encode( int org_size, ubyte *src, ubyte *dest ) { int i; ubyte c, oc; ubyte count; ubyte *dest_start; dest_start = dest; oc = *src++; count = 1; for (i=1; ibm_h; y++ ) { d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] ); if (d1 > 255) { large_rle = 1; break; } } rle_data=d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) ); if (rle_data==NULL) return 0; if (!large_rle) doffset = 4 + bmp->bm_h; else doffset = 4 + (2 * bmp->bm_h); // each row of rle'd bitmap has short instead of byte offset now for (y=0; ybm_h; y++ ) { d1= gr_rle_getsize( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y] ); if ( ((doffset+d1) > bmp->bm_w*bmp->bm_h) || (d1 > (large_rle?32767:255) ) ) { d_free(rle_data); return 0; } d = gr_rle_encode( bmp->bm_w, &bmp->bm_data[bmp->bm_w*y], &rle_data[doffset] ); Assert( d==d1 ); doffset += d; if (large_rle) *((short *)&(rle_data[(y*2)+4])) = (short)d; else rle_data[y+4] = d; } memcpy( rle_data, &doffset, 4 ); memcpy( bmp->bm_data, rle_data, doffset ); d_free(rle_data); bmp->bm_flags |= BM_FLAG_RLE; if (large_rle) bmp->bm_flags |= BM_FLAG_RLE_BIG; return 1; } #define MAX_CACHE_BITMAPS 32 typedef struct rle_cache_element { grs_bitmap * rle_bitmap; ubyte * rle_data; grs_bitmap * expanded_bitmap; int last_used; } rle_cache_element; int rle_cache_initialized = 0; int rle_counter = 0; int rle_next = 0; rle_cache_element rle_cache[MAX_CACHE_BITMAPS]; int rle_hits = 0; int rle_misses = 0; void rle_cache_close(void) { if (rle_cache_initialized) { int i; rle_cache_initialized = 0; for (i=0; ibm_data[4 + bmp->bm_h]; dbits = rle_temp_bitmap_1->bm_data; rle_temp_bitmap_1->bm_flags = bmp->bm_flags & (~BM_FLAG_RLE); for (i=0; i < bmp->bm_h; i++ ) { gr_rle_decode( sbits, dbits ); sbits += (int)bmp->bm_data[4+i]; dbits += bmp->bm_w; } } grs_bitmap * rle_expand_texture( grs_bitmap * bmp ) { int i; int lowest_count, lc; int least_recently_used; if (!rle_cache_initialized) rle_cache_init(); Assert( !(bmp->bm_flags & BM_FLAG_PAGED_OUT) ); lc = rle_counter; rle_counter++; if (rle_counter < 0) rle_counter = 0; if ( rle_counter < lc ) { for (i=0; i= MAX_CACHE_BITMAPS ) rle_next = 0; for (i=0; ibm_w, bmp->bm_h); rle_expand_texture_sub( bmp, rle_cache[least_recently_used].expanded_bitmap ); rle_cache[least_recently_used].rle_bitmap = bmp; rle_cache[least_recently_used].last_used = rle_counter; return rle_cache[least_recently_used].expanded_bitmap; } void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 ) { int i = 0, j; int count; ubyte color=0; if ( x2 < x1 ) return; count = 0; while ( i < x1 ) { color = *src++; if ( color == RLE_CODE ) return; if ( IS_RLE_CODE(color) ) { count = color & NOT_RLE_CODE; color = *src++; } else { // unique count = 1; } i += count; } count = i - x1; i = x1; // we know have '*count' pixels of 'color'. if ( x1+count > x2 ) { count = x2-x1+1; for ( j=0; j x2 ) { count = x2-x1+1; if (color != TRANSPARENCY_COLOR) { for ( j=0; jbm_flags & BM_FLAG_RLE_BIG; temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) ); if (rle_big) { // set ptrs to first lines ptr = bmp->bm_data + 4 + 2 * bmp->bm_h; ptr2 = temp + 4 + 2 * bmp->bm_h; } else { ptr = bmp->bm_data + 4 + bmp->bm_h; ptr2 = temp + 4 + bmp->bm_h; } for (i = 0; i < bmp->bm_h; i++) { start = ptr2; if (rle_big) line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i])); else line_size = bmp->bm_data[4 + i]; for (j = 0; j < line_size; j++) { if ( ! IS_RLE_CODE(ptr[j]) ) { if (ptr[j] == 0) { *ptr2++ = RLE_CODE | 1; *ptr2++ = 255; } else *ptr2++ = ptr[j]; } else { *ptr2++ = ptr[j]; if ((ptr[j] & NOT_RLE_CODE) == 0) break; j++; if (ptr[j] == 0) *ptr2++ = 255; else if (ptr[j] == 255) *ptr2++ = 0; else *ptr2++ = ptr[j]; } } if (rle_big) // set line size *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start); else temp[4 + i] = ptr2 - start; ptr += line_size; // go to next line } len = ptr2 - temp; *((int *)temp) = len; // set total size memcpy(bmp->bm_data, temp, len); d_free(temp); } /* * remaps all entries using colormap in an RLE bitmap without uncompressing it */ void rle_remap(grs_bitmap *bmp, ubyte *colormap) { int i, j, len, rle_big; unsigned char *ptr, *ptr2, *temp, *start; unsigned short line_size; rle_big = bmp->bm_flags & BM_FLAG_RLE_BIG; temp = d_malloc( MAX_BMP_SIZE(bmp->bm_w, bmp->bm_h) + 30000 ); if (rle_big) { // set ptrs to first lines ptr = bmp->bm_data + 4 + 2 * bmp->bm_h; ptr2 = temp + 4 + 2 * bmp->bm_h; } else { ptr = bmp->bm_data + 4 + bmp->bm_h; ptr2 = temp + 4 + bmp->bm_h; } for (i = 0; i < bmp->bm_h; i++) { start = ptr2; if (rle_big) line_size = INTEL_SHORT(*((unsigned short *)&bmp->bm_data[4 + 2 * i])); else line_size = bmp->bm_data[4 + i]; for (j = 0; j < line_size; j++) { if ( ! IS_RLE_CODE(ptr[j])) { if (IS_RLE_CODE(colormap[ptr[j]])) *ptr2++ = RLE_CODE | 1; // add "escape sequence" *ptr2++ = colormap[ptr[j]]; // translate } else { *ptr2++ = ptr[j]; // just copy current rle code if ((ptr[j] & NOT_RLE_CODE) == 0) break; j++; *ptr2++ = colormap[ptr[j]]; // translate } } if (rle_big) // set line size *((unsigned short *)&temp[4 + 2 * i]) = INTEL_SHORT(ptr2 - start); else temp[4 + i] = ptr2 - start; ptr += line_size; // go to next line } len = ptr2 - temp; *((int *)temp) = len; // set total size memcpy(bmp->bm_data, temp, len); d_free(temp); } dxx-rebirth-0.58.1-d1x/2d/scalec.c000066400000000000000000000257671217717257200164760ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include "gr.h" #include "grdef.h" #include "rle.h" // John's new stuff below here.... int scale_error_term; int scale_initial_pixel_count; int scale_adj_up; int scale_adj_down; int scale_final_pixel_count; int scale_ydelta_minus_1; int scale_whole_step; ubyte * scale_source_ptr; ubyte * scale_dest_ptr; ubyte scale_rle_data[640]; void scale_up_bitmap(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ); void scale_up_bitmap_rle(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ); void rls_stretch_scanline_setup( int XDelta, int YDelta ); void rls_stretch_scanline(void); void decode_row( grs_bitmap * bmp, int y ) { int i, offset=4+bmp->bm_h; for (i=0; ibm_data[4+i]; gr_rle_decode( &bmp->bm_data[offset], scale_rle_data ); } void scale_up_bitmap(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) { fix dv, v; int y; if (orientation & 1) { int t; t = u0; u0 = u1; u1 = t; } if (orientation & 2) { int t; t = v0; v0 = v1; v1 = t; if (v1 < v0) v0--; } v = v0; dv = (v1-v0) / (y1-y0); rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) ); if ( scale_ydelta_minus_1 < 1 ) return; v = v0; for (y=y0; y<=y1; y++ ) { scale_source_ptr = &source_bmp->bm_data[source_bmp->bm_rowsize*f2i(v)+f2i(u0)]; scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0]; rls_stretch_scanline(); v += dv; } } void scale_up_bitmap_rle(grs_bitmap *source_bmp, grs_bitmap *dest_bmp, int x0, int y0, int x1, int y1, fix u0, fix v0, fix u1, fix v1, int orientation ) { fix dv, v; int y, last_row = -1; if (orientation & 1) { int t; t = u0; u0 = u1; u1 = t; } if (orientation & 2) { int t; t = v0; v0 = v1; v1 = t; if (v1 < v0) v0--; } dv = (v1-v0) / (y1-y0); rls_stretch_scanline_setup( (int)(x1-x0), f2i(u1)-f2i(u0) ); if ( scale_ydelta_minus_1 < 1 ) return; v = v0; for (y=y0; y<=y1; y++ ) { if ( f2i(v) != last_row ) { last_row = f2i(v); decode_row( source_bmp, last_row ); } scale_source_ptr = &scale_rle_data[f2i(u0)]; scale_dest_ptr = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0]; rls_stretch_scanline( ); v += dv; } } void rls_stretch_scanline_setup( int XDelta, int YDelta ) { scale_ydelta_minus_1 = YDelta - 1; /* X major line */ /* Minimum # of pixels in a run in this line */ scale_whole_step = XDelta / YDelta; /* Error term adjust each time Y steps by 1; used to tell when one extra pixel should be drawn as part of a run, to account for fractional steps along the X axis per 1-pixel steps along Y */ scale_adj_up = (XDelta % YDelta) * 2; /* Error term adjust when the error term turns over, used to factor out the X step made at that time */ scale_adj_down = YDelta * 2; /* Initial error term; reflects an initial step of 0.5 along the Y axis */ scale_error_term = (XDelta % YDelta) - (YDelta * 2); /* The initial and last runs are partial, because Y advances only 0.5 for these runs, rather than 1. Divide one full run, plus the initial pixel, between the initial and last runs */ scale_initial_pixel_count = (scale_whole_step / 2) + 1; scale_final_pixel_count = scale_initial_pixel_count; /* If the basic run length is even and there's no fractional advance, we have one pixel that could go to either the initial or last partial run, which we'll arbitrarily allocate to the last run */ if ((scale_adj_up == 0) && ((scale_whole_step & 0x01) == 0)) { scale_initial_pixel_count--; } /* If there're an odd number of pixels per run, we have 1 pixel that can't be allocated to either the initial or last partial run, so we'll add 0.5 to error term so this pixel will be handled by the normal full-run loop */ if ((scale_whole_step & 0x01) != 0) { scale_error_term += YDelta; } } void rls_stretch_scanline( ) { ubyte c, *src_ptr, *dest_ptr; int i, j, len, ErrorTerm, initial_count, final_count; // Draw the first, partial run of pixels src_ptr = scale_source_ptr; dest_ptr = scale_dest_ptr; ErrorTerm = scale_error_term; initial_count = scale_initial_pixel_count; final_count = scale_final_pixel_count; c = *src_ptr++; if ( c != TRANSPARENCY_COLOR ) { for (i=0; i 0) { len++; ErrorTerm -= scale_adj_down; // reset the error term } // Draw this run o' pixels c = *src_ptr++; if ( c != TRANSPARENCY_COLOR ) { for (i=len; i>0; i-- ) *dest_ptr++ = c; } else { dest_ptr += len; } } // Draw the final run of pixels c = *src_ptr++; if ( c != TRANSPARENCY_COLOR ) { for (i=0; ibm_data[source_bmp->bm_rowsize*f2i(v)]; dbits = &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0]; u = u0; v += dv; for (x=x0; x<=x1; x++ ) { c = sbits[u >> 16]; if (c != TRANSPARENCY_COLOR) *dbits = c; dbits++; u += du; } } } void scale_row_transparent( ubyte * sbits, ubyte * dbits, int width, fix u, fix du ) { int i; ubyte c; ubyte *dbits_end = &dbits[width-1]; if ( du < F1_0 ) { // Scaling up. fix next_u; int next_u_int; next_u_int = f2i(u)+1; c = sbits[ next_u_int ]; next_u = i2f(next_u_int); if ( c != TRANSPARENCY_COLOR ) goto NonTransparent; Transparent: while (1) { dbits++; if ( dbits > dbits_end ) return; u += du; if ( u > next_u ) { next_u_int = f2i(u)+1; c = sbits[ next_u_int ]; next_u = i2f(next_u_int); if ( c != TRANSPARENCY_COLOR ) goto NonTransparent; } } return; NonTransparent: while (1) { *dbits++ = c; if ( dbits > dbits_end ) return; u += du; if ( u > next_u ) { next_u_int = f2i(u)+1; c = sbits[ next_u_int ]; next_u = i2f(next_u_int); if ( c == TRANSPARENCY_COLOR ) goto Transparent; } } return; } else { for ( i=0; i= 0); //Int3(); //this should be checked in higher-level routine return; } for (y=y0; y<=y1; y++ ) { if ( f2i(v) != last_row ) { last_row = f2i(v); decode_row( source_bmp, last_row ); } scale_row_transparent( scale_rle_data, &dest_bmp->bm_data[dest_bmp->bm_rowsize*y+x0], x1-x0+1, u0, du ); v += dv; } } #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (fixmuldiv((x)-(x0),(y1)-(y0),(x1)-(x0))+(y0)) // Scales bitmap, bp, into vertbuf[0] to vertbuf[1] void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf, int orientation ) { grs_bitmap * dbp = &grd_curcanv->cv_bitmap; fix x0, y0, x1, y1; fix u0, v0, u1, v1; fix clipped_x0, clipped_y0, clipped_x1, clipped_y1; fix clipped_u0, clipped_v0, clipped_u1, clipped_v1; fix xmin, xmax, ymin, ymax; int dx0, dy0, dx1, dy1; int dtemp; // Set initial variables.... x0 = vertbuf[0].x; y0 = vertbuf[0].y; x1 = vertbuf[2].x; y1 = vertbuf[2].y; xmin = 0; ymin = 0; xmax = i2f(dbp->bm_w)-fl2f(.5); ymax = i2f(dbp->bm_h)-fl2f(.5); u0 = i2f(0); v0 = i2f(0); u1 = i2f(bp->bm_w-1); v1 = i2f(bp->bm_h-1); // Check for obviously offscreen bitmaps... if ( (y1<=y0) || (x1<=x0) ) return; if ( (x1<0 ) || (x0>=xmax) ) return; if ( (y1<0 ) || (y0>=ymax) ) return; clipped_u0 = u0; clipped_v0 = v0; clipped_u1 = u1; clipped_v1 = v1; clipped_x0 = x0; clipped_y0 = y0; clipped_x1 = x1; clipped_y1 = y1; // Clip the left, moving u0 right as necessary if ( x0 < xmin ) { clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1); clipped_x0 = xmin; } // Clip the right, moving u1 left as necessary if ( x1 > xmax ) { clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1); clipped_x1 = xmax; } // Clip the top, moving v0 down as necessary if ( y0 < ymin ) { clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1); clipped_y0 = ymin; } // Clip the bottom, moving v1 up as necessary if ( y1 > ymax ) { clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1); clipped_y1 = ymax; } dx0 = f2i(clipped_x0); dx1 = f2i(clipped_x1); dy0 = f2i(clipped_y0); dy1 = f2i(clipped_y1); if (dx1<=dx0) return; if (dy1<=dy0) return; dtemp = f2i(clipped_u1)-f2i(clipped_u0); if ( bp->bm_flags & BM_FLAG_RLE ) { if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) ) scale_up_bitmap_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); else scale_bitmap_c_rle(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); } else { if ( (dtemp < (f2i(clipped_x1)-f2i(clipped_x0))) && (dtemp>0) ) scale_up_bitmap(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); else scale_bitmap_c(bp, dbp, dx0, dy0, dx1, dy1, clipped_u0, clipped_v0, clipped_u1, clipped_v1, orientation ); } } dxx-rebirth-0.58.1-d1x/3d/000077500000000000000000000000001217717257200150605ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/3d/clipper.c000066400000000000000000000121731217717257200166660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include "3d.h" #include "globvars.h" #include "clipper.h" #include "dxxerror.h" int free_point_num=0; g3s_point temp_points[MAX_POINTS_IN_POLY]; g3s_point *free_points[MAX_POINTS_IN_POLY]; void init_free_points(void) { int i; for (i=0;ip3_flags = PF_TEMP_POINT; return p; } void free_temp_point(g3s_point *p) { Assert(p->p3_flags & PF_TEMP_POINT); free_points[--free_point_num] = p; p->p3_flags &= ~PF_TEMP_POINT; } //clips an edge against one plane. g3s_point *clip_edge(int plane_flag,g3s_point *on_pnt,g3s_point *off_pnt) { fix psx_ratio; fix a,b,kn,kd; g3s_point *tmp; //compute clipping value k = (xs-zs) / (xs-xe-zs+ze) //use x or y as appropriate, and negate x/y value as appropriate if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) { a = on_pnt->p3_x; b = off_pnt->p3_x; } else { a = on_pnt->p3_y; b = off_pnt->p3_y; } if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) { a = -a; b = -b; } kn = a - on_pnt->p3_z; //xs-zs kd = kn - b + off_pnt->p3_z; //xs-zs-xe+ze tmp = get_temp_point(); psx_ratio = fixdiv( kn, kd ); // PSX_HACK!!!! // tmp->p3_x = on_pnt->p3_x + fixmuldiv(off_pnt->p3_x-on_pnt->p3_x,kn,kd); // tmp->p3_y = on_pnt->p3_y + fixmuldiv(off_pnt->p3_y-on_pnt->p3_y,kn,kd); tmp->p3_x = on_pnt->p3_x + fixmul( (off_pnt->p3_x-on_pnt->p3_x), psx_ratio); tmp->p3_y = on_pnt->p3_y + fixmul( (off_pnt->p3_y-on_pnt->p3_y), psx_ratio); if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT)) tmp->p3_z = tmp->p3_y; else tmp->p3_z = tmp->p3_x; if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT)) tmp->p3_z = -tmp->p3_z; if (on_pnt->p3_flags & PF_UVS) { // PSX_HACK!!!! // tmp->p3_u = on_pnt->p3_u + fixmuldiv(off_pnt->p3_u-on_pnt->p3_u,kn,kd); // tmp->p3_v = on_pnt->p3_v + fixmuldiv(off_pnt->p3_v-on_pnt->p3_v,kn,kd); tmp->p3_u = on_pnt->p3_u + fixmul((off_pnt->p3_u-on_pnt->p3_u), psx_ratio); tmp->p3_v = on_pnt->p3_v + fixmul((off_pnt->p3_v-on_pnt->p3_v), psx_ratio); tmp->p3_flags |= PF_UVS; } if (on_pnt->p3_flags & PF_LS) { // PSX_HACK // tmp->p3_r = on_pnt->p3_r + fixmuldiv(off_pnt->p3_r-on_pnt->p3_r,kn,kd); // tmp->p3_g = on_pnt->p3_g + fixmuldiv(off_pnt->p3_g-on_pnt->p3_g,kn,kd); // tmp->p3_b = on_pnt->p3_b + fixmuldiv(off_pnt->p3_b-on_pnt->p3_b,kn,kd); tmp->p3_l = on_pnt->p3_l + fixmul((off_pnt->p3_l-on_pnt->p3_l), psx_ratio); tmp->p3_flags |= PF_LS; } g3_code_point(tmp); return tmp; } //clips a line to the viewing pyramid. void clip_line(g3s_point **p0,g3s_point **p1,ubyte codes_or) { int plane_flag; g3s_point *old_p1; //might have these left over (*p0)->p3_flags &= ~(PF_UVS|PF_LS); (*p1)->p3_flags &= ~(PF_UVS|PF_LS); for (plane_flag=1;plane_flag<16;plane_flag<<=1) if (codes_or & plane_flag) { if ((*p0)->p3_codes & plane_flag) {g3s_point *t=*p0; *p0=*p1; *p1=t;} //swap! old_p1 = *p1; *p1 = clip_edge(plane_flag,*p0,*p1); if (old_p1->p3_flags & PF_TEMP_POINT) free_temp_point(old_p1); } } int clip_plane(int plane_flag,g3s_point **src,g3s_point **dest,int *nv,g3s_codes *cc) { int i; g3s_point **save_dest=dest; //copy first two verts to end src[*nv] = src[0]; src[*nv+1] = src[1]; cc->uand = 0xff; cc->uor = 0; for (i=1;i<=*nv;i++) { if (src[i]->p3_codes & plane_flag) { //cur point off? if (! (src[i-1]->p3_codes & plane_flag)) { //prev not off? *dest = clip_edge(plane_flag,src[i-1],src[i]); cc->uor |= (*dest)->p3_codes; cc->uand &= (*dest)->p3_codes; dest++; } if (! (src[i+1]->p3_codes & plane_flag)) { *dest = clip_edge(plane_flag,src[i+1],src[i]); cc->uor |= (*dest)->p3_codes; cc->uand &= (*dest)->p3_codes; dest++; } //see if must free discarded point if (src[i]->p3_flags & PF_TEMP_POINT) free_temp_point(src[i]); } else { //cur not off, copy to dest buffer *dest++ = src[i]; cc->uor |= src[i]->p3_codes; cc->uand &= src[i]->p3_codes; } } return (dest-save_dest); } g3s_point **clip_polygon(g3s_point **src,g3s_point **dest,int *nv,g3s_codes *cc) { int plane_flag; g3s_point **t; for (plane_flag=1;plane_flag<16;plane_flag<<=1) if (cc->uor & plane_flag) { *nv = clip_plane(plane_flag,src,dest,nv,cc); if (cc->uand) //clipped away return dest; t = src; src = dest; dest = t; } return src; //we swapped after we copied } dxx-rebirth-0.58.1-d1x/3d/clipper.h000066400000000000000000000027541217717257200166770ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/3d/clipper.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:05 $ * * Header for clipper.c * * $Log: clipper.h,v $ * Revision 1.1.1.1 2006/03/17 19:39:05 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 21:57:51 donut * Import of d1x 1.37 source. * * Revision 1.1 1995/05/05 08:50:13 allender * Initial revision * * Revision 1.1 1995/04/17 19:56:58 matt * Initial revision * * */ #ifndef _CLIPPER_H #define _CLIPPER_H extern void free_temp_point(g3s_point *p); extern g3s_point **clip_polygon(g3s_point **src,g3s_point **dest,int *nv,g3s_codes *cc); extern void init_free_points(void); extern void clip_line(g3s_point **p0,g3s_point **p1,ubyte codes_or); #endif dxx-rebirth-0.58.1-d1x/3d/draw.c000066400000000000000000000176041217717257200161710ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Drawing routines * */ #include "dxxerror.h" #include "3d.h" #include "globvars.h" #include "texmap.h" #include "clipper.h" tmap_drawer_type tmap_drawer_ptr = draw_tmap; flat_drawer_type flat_drawer_ptr = gr_upoly_tmap; line_drawer_type line_drawer_ptr = gr_line; //specifies 2d drawing routines to use instead of defaults. Passing //NULL for either or both restores defaults void g3_set_special_render(tmap_drawer_type tmap_drawer,flat_drawer_type flat_drawer,line_drawer_type line_drawer) { tmap_drawer_ptr = (tmap_drawer)?tmap_drawer:draw_tmap; flat_drawer_ptr = (flat_drawer)?flat_drawer:gr_upoly_tmap; line_drawer_ptr = (line_drawer)?line_drawer:gr_line; } #ifndef OGL //deal with a clipped line bool must_clip_line(g3s_point *p0,g3s_point *p1,ubyte codes_or) { bool ret; if ((p0->p3_flags&PF_TEMP_POINT) || (p1->p3_flags&PF_TEMP_POINT)) ret = 0; //line has already been clipped, so give up else { clip_line(&p0,&p1,codes_or); ret = g3_draw_line(p0,p1); } //free temp points if (p0->p3_flags & PF_TEMP_POINT) free_temp_point(p0); if (p1->p3_flags & PF_TEMP_POINT) free_temp_point(p1); return ret; } //draws a line. takes two points. returns true if drew bool g3_draw_line(g3s_point *p0,g3s_point *p1) { ubyte codes_or; if (p0->p3_codes & p1->p3_codes) return 0; codes_or = p0->p3_codes | p1->p3_codes; if (codes_or & CC_BEHIND) return must_clip_line(p0,p1,codes_or); if (!(p0->p3_flags&PF_PROJECTED)) g3_project_point(p0); if (p0->p3_flags&PF_OVERFLOW) return must_clip_line(p0,p1,codes_or); if (!(p1->p3_flags&PF_PROJECTED)) g3_project_point(p1); if (p1->p3_flags&PF_OVERFLOW) return must_clip_line(p0,p1,codes_or); return (bool) (*line_drawer_ptr)(p0->p3_sx,p0->p3_sy,p1->p3_sx,p1->p3_sy); } #endif //returns true if a plane is facing the viewer. takes the unrotated surface //normal of the plane, and a point on it. The normal need not be normalized bool g3_check_normal_facing(vms_vector *v,vms_vector *norm) { vms_vector tempv; vm_vec_sub(&tempv,&View_position,v); return (vm_vec_dot(&tempv,norm) > 0); } bool do_facing_check(vms_vector *norm,g3s_point **vertlist,vms_vector *p) { if (norm) { //have normal Assert(norm->x || norm->y || norm->z); return g3_check_normal_facing(p,norm); } else { //normal not specified, so must compute vms_vector tempv; //get three points (rotated) and compute normal vm_vec_perp(&tempv,&vertlist[0]->p3_vec,&vertlist[1]->p3_vec,&vertlist[2]->p3_vec); return (vm_vec_dot(&tempv,&vertlist[1]->p3_vec) < 0); } } //like g3_draw_poly(), but checks to see if facing. If surface normal is //NULL, this routine must compute it, which will be slow. It is better to //pre-compute the normal, and pass it to this function. When the normal //is passed, this function works like g3_check_normal_facing() plus //g3_draw_poly(). //returns -1 if not facing, 1 if off screen, 0 if drew bool g3_check_and_draw_poly(int nv,g3s_point **pointlist,vms_vector *norm,vms_vector *pnt) { if (do_facing_check(norm,pointlist,pnt)) return g3_draw_poly(nv,pointlist); else return 255; } bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm,vms_vector *norm,vms_vector *pnt) { if (do_facing_check(norm,pointlist,pnt)) return g3_draw_tmap(nv,pointlist,uvl_list,light_rgb,bm); else return 255; } //deal with face that must be clipped bool must_clip_flat_face(int nv,g3s_codes cc) { int i; bool ret=0; g3s_point **bufptr; bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc); if (nv>0 && !(cc.uor&CC_BEHIND) && !cc.uand) { for (i=0;ip3_flags&PF_PROJECTED)) g3_project_point(p); if (p->p3_flags&PF_OVERFLOW) { ret = 1; goto free_points; } Vertex_list[i*2] = p->p3_sx; Vertex_list[i*2+1] = p->p3_sy; } (*flat_drawer_ptr)(nv,(int *)Vertex_list); } else ret=1; //free temp points free_points: ; for (i=0;ip3_flags & PF_TEMP_POINT) free_temp_point(Vbuf1[i]); // Assert(free_point_num==0); return ret; } #ifndef OGL //draw a flat-shaded face. //returns 1 if off screen, 0 if drew bool g3_draw_poly(int nv,g3s_point **pointlist) { int i; g3s_point **bufptr; g3s_codes cc; cc.uor = 0; cc.uand = 0xff; bufptr = Vbuf0; for (i=0;ip3_codes; cc.uor |= bufptr[i]->p3_codes; } if (cc.uand) return 1; //all points off screen if (cc.uor) return must_clip_flat_face(nv,cc); //now make list of 2d coords (& check for overflow) for (i=0;ip3_flags&PF_PROJECTED)) g3_project_point(p); if (p->p3_flags&PF_OVERFLOW) return must_clip_flat_face(nv,cc); Vertex_list[i*2] = p->p3_sx; Vertex_list[i*2+1] = p->p3_sy; } (*flat_drawer_ptr)(nv,(int *)Vertex_list); return 0; //say it drew } bool must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm); //draw a texture-mapped face. //returns 1 if off screen, 0 if drew bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm) { int i; g3s_point **bufptr; g3s_codes cc; cc.uor = 0; cc.uand = 0xff; bufptr = Vbuf0; for (i=0;ip3_codes; cc.uor |= p->p3_codes; p->p3_u = uvl_list[i].u; p->p3_v = uvl_list[i].v; p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3; p->p3_flags |= PF_UVS + PF_LS; } if (cc.uand) return 1; //all points off screen if (cc.uor) return must_clip_tmap_face(nv,cc,bm); //now make list of 2d coords (& check for overflow) for (i=0;ip3_flags&PF_PROJECTED)) g3_project_point(p); if (p->p3_flags&PF_OVERFLOW) { Int3(); //should not overflow after clip return 255; } } (*tmap_drawer_ptr)(bm,nv,bufptr); return 0; //say it drew } #endif bool must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm) { g3s_point **bufptr; int i; bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc); if (nv && !(cc.uor&CC_BEHIND) && !cc.uand) { for (i=0;ip3_flags&PF_PROJECTED)) g3_project_point(p); if (p->p3_flags&PF_OVERFLOW) { Int3(); //should not overflow after clip goto free_points; } } (*tmap_drawer_ptr)(bm,nv,bufptr); } free_points: ; for (i=0;ip3_flags & PF_TEMP_POINT) free_temp_point(bufptr[i]); // Assert(free_point_num==0); return 0; } #ifndef __powerc int checkmuldiv(fix *r,fix a,fix b,fix c); #endif #ifndef OGL //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d //radius, but not to the distance from the eye int g3_draw_sphere(g3s_point *pnt,fix rad) { if (! (pnt->p3_codes & CC_BEHIND)) { if (! (pnt->p3_flags & PF_PROJECTED)) g3_project_point(pnt); if (! (pnt->p3_codes & PF_OVERFLOW)) { fix r2,t; r2 = fixmul(rad,Matrix_scale.x); #ifndef __powerc if (checkmuldiv(&t,r2,Canv_w2,pnt->p3_z)) return gr_disk(pnt->p3_sx,pnt->p3_sy,t); #else if (pnt->p3_z == 0) return 0; return gr_disk(pnt->p3_sx, pnt->p3_sy, fl2f(((f2fl(r2) * fCanv_w2) / f2fl(pnt->p3_z)))); #endif } } return 0; } #endif dxx-rebirth-0.58.1-d1x/3d/globvars.c000066400000000000000000000037661217717257200170570ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/3d/globvars.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:05 $ * * Global variables for 3d * * $Log: globvars.c,v $ * Revision 1.1.1.1 2006/03/17 19:39:05 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 21:57:45 donut * Import of d1x 1.37 source. * * Revision 1.2 1995/09/13 11:30:47 allender * added fCanv_w2 and vCanv_h2 for PPC implementation * * Revision 1.1 1995/05/05 08:50:48 allender * Initial revision * * Revision 1.1 1995/04/17 04:24:57 matt * Initial revision * * */ #include "3d.h" #include "globvars.h" vms_vector View_position; fix View_zoom; vms_matrix Unscaled_matrix; //before scaling vms_matrix View_matrix; vms_vector Window_scale; //scaling for window aspect vms_vector Matrix_scale; //how the matrix is scaled, window_scale * zoom int Canvas_width; //the actual width int Canvas_height; //the actual height fix Canv_w2; //fixed-point width/2 fix Canv_h2; //fixed-point height/2 #ifdef __powerc double fCanv_w2; double fCanv_h2; #endif //vertex buffers for polygon drawing and clipping g3s_point * Vbuf0[MAX_POINTS_IN_POLY]; g3s_point *Vbuf1[MAX_POINTS_IN_POLY]; //list of 2d coords fix Vertex_list[MAX_POINTS_IN_POLY*2]; dxx-rebirth-0.58.1-d1x/3d/globvars.h000066400000000000000000000036421217717257200170550ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/3d/globvars.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:05 $ * * Private (internal) header for 3d library * * $Log: globvars.h,v $ * Revision 1.1.1.1 2006/03/17 19:39:05 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 21:57:51 donut * Import of d1x 1.37 source. * * Revision 1.2 1995/09/13 11:31:19 allender * added fCanv_w2 and vCanv_h2 for PPC implementation * * Revision 1.1 1995/05/05 08:51:02 allender * Initial revision * * Revision 1.1 1995/04/17 04:07:58 matt * Initial revision * * */ #ifndef _GLOBVARS_H #define _GLOBVARS_H #define MAX_POINTS_IN_POLY 100 extern int Canvas_width,Canvas_height; //the actual width & height extern fix Canv_w2,Canv_h2; //fixed-point width,height/2 #ifdef __powerc extern double fCanv_w2, fCanv_h2; #endif extern vms_vector Window_scale; extern int free_point_num; extern fix View_zoom; extern vms_vector View_position,Matrix_scale; extern vms_matrix View_matrix,Unscaled_matrix; //vertex buffers for polygon drawing and clipping extern g3s_point *Vbuf0[]; extern g3s_point *Vbuf1[]; //list of 2d coords extern fix Vertex_list[]; #endif dxx-rebirth-0.58.1-d1x/3d/instance.c000066400000000000000000000045351217717257200170370ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Instancing routines * */ #include #include "dxxerror.h" #include "3d.h" #include "globvars.h" #define MAX_INSTANCE_DEPTH 5 struct instance_context { vms_matrix m; vms_vector p; } instance_stack[MAX_INSTANCE_DEPTH]; int instance_depth = 0; //instance at specified point with specified orientation //if matrix==NULL, don't modify matrix. This will be like doing an offset void g3_start_instance_matrix(vms_vector *pos,vms_matrix *orient) { vms_vector tempv; vms_matrix tempm,tempm2; Assert(instance_depth= 0); View_position = instance_stack[instance_depth].p; View_matrix = instance_stack[instance_depth].m; } dxx-rebirth-0.58.1-d1x/3d/interp.c000066400000000000000000000375501217717257200165370ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Polygon object interpreter * */ #include #include "dxxerror.h" #include "3d.h" #include "globvars.h" #include "gr.h" #include "byteswap.h" #include "polyobj.h" #define OP_EOF 0 //eof #define OP_DEFPOINTS 1 //defpoints #define OP_FLATPOLY 2 //flat-shaded polygon #define OP_TMAPPOLY 3 //texture-mapped polygon #define OP_SORTNORM 4 //sort by normal #define OP_RODBM 5 //rod bitmap #define OP_SUBCALL 6 //call a subobject #define OP_DEFP_START 7 //defpoints with start #define OP_GLOW 8 //glow value for next poly #define N_OPCODES (sizeof(opcode_table) / sizeof(*opcode_table)) #define MAX_POINTS_PER_POLY 25 short highest_texture_num; int g3d_interp_outline; g3s_point *Interp_point_list = NULL; #define MAX_INTERP_COLORS 100 //this is a table of mappings from RGB15 to palette colors struct {short pal_entry,rgb15;} interp_color_table[MAX_INTERP_COLORS]; int n_interp_colors=0; //gives the interpreter an array of points to use void g3_set_interp_points(g3s_point *pointlist) { Interp_point_list = pointlist; } #define w(p) (*((short *) (p))) #define wp(p) ((short *) (p)) #define fp(p) ((fix *) (p)) #define vp(p) ((vms_vector *) (p)) void rotate_point_list(g3s_point *dest,vms_vector *src,int n) { while (n--) g3_rotate_point(dest++,src++); } vms_angvec zero_angles = {0,0,0}; g3s_point *point_list[MAX_POINTS_PER_POLY]; int glow_num = -1; // check a polymodel for it's color and return it int g3_poly_get_color(void *model_ptr) { ubyte *p = model_ptr; int color = 0; while (w(p) != OP_EOF) switch (w(p)) { case OP_DEFPOINTS: p += w(p+2)*sizeof(struct vms_vector) + 4; break; case OP_DEFP_START: p += w(p+2)*sizeof(struct vms_vector) + 8; break; case OP_FLATPOLY: { int nv = w(p+2); if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) color = (w(p+28)); p += 30 + ((nv&~1)+1)*2; break; } case OP_TMAPPOLY: { int nv = w(p+2); p += 30 + ((nv&~1)+1)*2 + nv*12; break; } case OP_SORTNORM: if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) //facing color = g3_poly_get_color(p+w(p+28)); else //not facing color = g3_poly_get_color(p+w(p+30)); p += 32; break; case OP_RODBM: p+=36; break; case OP_SUBCALL: color = g3_poly_get_color(p+w(p+16)); p += 20; break; case OP_GLOW: p += 4; break; default: ; } return color; } //calls the object interpreter to render an object. The object renderer //is really a seperate pipeline. returns true if drew bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb model_light,fix *glow_values) { ubyte *p = model_ptr; glow_num = -1; //glow off by default while (w(p) != OP_EOF) switch (w(p)) { case OP_DEFPOINTS: { int n = w(p+2); rotate_point_list(Interp_point_list,vp(p+4),n); p += n*sizeof(struct vms_vector) + 4; break; } case OP_DEFP_START: { int n = w(p+2); int s = w(p+4); rotate_point_list(&Interp_point_list[s],vp(p+8),n); p += n*sizeof(struct vms_vector) + 8; break; } case OP_FLATPOLY: { int nv = w(p+2); Assert( nv < MAX_POINTS_PER_POLY ); if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) { int i; gr_setcolor(w(p+28)); for (i=0;i 0) { int i; g3s_lrgb light, *lrgb_list; MALLOC(lrgb_list, g3s_lrgb, nv); //calculate light from surface normal if (glow_num < 0) //no glow { light.r = light.g = light.b = -vm_vec_dot(&View_matrix.fvec,vp(p+16)); light.r = f1_0/4 + (light.r*3)/4; light.r = fixmul(light.r,model_light.r); light.g = f1_0/4 + (light.g*3)/4; light.g = fixmul(light.g,model_light.g); light.b = f1_0/4 + (light.b*3)/4; light.b = fixmul(light.b,model_light.b); } else //yes glow { light.r = light.g = light.b = glow_values[glow_num]; glow_num = -1; } //now poke light into l values uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2); for (i=0;i 0) { //facing //draw back then front g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values); g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values); } else { //not facing. draw front then back g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values); g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values); } p += 32; break; case OP_RODBM: { g3s_point rod_bot_p,rod_top_p; g3s_lrgb rodbm_light = { f1_0, f1_0, f1_0 }; g3_rotate_point(&rod_bot_p,vp(p+20)); g3_rotate_point(&rod_top_p,vp(p+4)); g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),rodbm_light); p+=36; break; } case OP_SUBCALL: { vms_angvec *a; if (anim_angles) a = &anim_angles[w(p+2)]; else a = &zero_angles; g3_start_instance_angles(vp(p+4),a); g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values); g3_done_instance(); p += 20; break; } case OP_GLOW: if (glow_values) glow_num = w(p+2); p += 4; break; default: ; } return 1; } #ifndef NDEBUG int nest_count; #endif //alternate interpreter for morphing object bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb model_light,vms_vector *new_points) { ubyte *p = model_ptr; fix *glow_values = NULL; glow_num = -1; //glow off by default while (w(p) != OP_EOF) switch (w(p)) { case OP_DEFPOINTS: { int n = w(p+2); rotate_point_list(Interp_point_list,new_points,n); p += n*sizeof(struct vms_vector) + 4; break; } case OP_DEFP_START: { int n = w(p+2); int s = w(p+4); rotate_point_list(&Interp_point_list[s],new_points,n); p += n*sizeof(struct vms_vector) + 8; break; } case OP_FLATPOLY: { int nv = w(p+2); int i,ntris; gr_setcolor(55/*w(p+28)*/); for (i=0;i<2;i++) point_list[i] = Interp_point_list + wp(p+30)[i]; for (ntris=nv-2;ntris;ntris--) { point_list[2] = Interp_point_list + wp(p+30)[i++]; g3_check_and_draw_poly(3,point_list,NULL,NULL); point_list[1] = point_list[2]; } p += 30 + ((nv&~1)+1)*2; break; } case OP_TMAPPOLY: { int nv = w(p+2); g3s_uvl *uvl_list; g3s_lrgb light, *lrgb_list; g3s_uvl morph_uvls[3]; int i,ntris; MALLOC(lrgb_list, g3s_lrgb, nv); //calculate light from surface normal if (glow_num < 0) //no glow { light.r = light.g = light.b = -vm_vec_dot(&View_matrix.fvec,vp(p+16)); light.r = f1_0/4 + (light.r*3)/4; light.r = fixmul(light.r,model_light.r); light.g = f1_0/4 + (light.g*3)/4; light.g = fixmul(light.g,model_light.g); light.b = f1_0/4 + (light.b*3)/4; light.b = fixmul(light.b,model_light.b); } else //yes glow { light.r = light.g = light.b = glow_values[glow_num]; glow_num = -1; } //now poke light into l values uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2); for (i=0;i 0) { //facing //draw back then front g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points); g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points); } else { //not facing. draw front then back g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points); g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points); } p += 32; break; case OP_RODBM: { g3s_point rod_bot_p,rod_top_p; g3s_lrgb rodbm_light = { f1_0, f1_0, f1_0 }; g3_rotate_point(&rod_bot_p,vp(p+20)); g3_rotate_point(&rod_top_p,vp(p+4)); g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),rodbm_light); p+=36; break; } case OP_SUBCALL: { vms_angvec *a; if (anim_angles) a = &anim_angles[w(p+2)]; else a = &zero_angles; g3_start_instance_angles(vp(p+4),a); g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values); g3_done_instance(); p += 20; break; } case OP_GLOW: if (glow_values) glow_num = w(p+2); p += 4; break; } return 1; } void init_model_sub(ubyte *p) { Assert(++nest_count < 1000); while (w(p) != OP_EOF) { switch (w(p)) { case OP_DEFPOINTS: { int n = w(p+2); p += n*sizeof(struct vms_vector) + 4; break; } case OP_DEFP_START: { int n = w(p+2); p += n*sizeof(struct vms_vector) + 8; break; } case OP_FLATPOLY: { int nv = w(p+2); Assert(nv > 2); //must have 3 or more points *wp(p+28) = (short)gr_find_closest_color_15bpp(w(p+28)); p += 30 + ((nv&~1)+1)*2; break; } case OP_TMAPPOLY: { int nv = w(p+2); Assert(nv > 2); //must have 3 or more points if (w(p+28) > highest_texture_num) highest_texture_num = w(p+28); p += 30 + ((nv&~1)+1)*2 + nv*12; break; } case OP_SORTNORM: init_model_sub(p+w(p+28)); init_model_sub(p+w(p+30)); p += 32; break; case OP_RODBM: p += 36; break; case OP_SUBCALL: { init_model_sub(p+w(p+16)); p += 20; break; } case OP_GLOW: p += 4; break; } } } //init code for bitmap models void g3_init_polygon_model(void *model_ptr) { #ifndef NDEBUG nest_count = 0; #endif highest_texture_num = -1; init_model_sub((ubyte *) model_ptr); } #ifdef WORDS_BIGENDIAN void short_swap(short *s) { *s = SWAPSHORT(*s); } void fix_swap(fix *f) { *f = (fix)SWAPINT((int)*f); } void vms_vector_swap(vms_vector *v) { fix_swap(fp(&v->x)); fix_swap(fp(&v->y)); fix_swap(fp(&v->z)); } void fixang_swap(fixang *f) { *f = (fixang)SWAPSHORT((short)*f); } void vms_angvec_swap(vms_angvec *v) { fixang_swap(&v->p); fixang_swap(&v->b); fixang_swap(&v->h); } void swap_polygon_model_data(ubyte *data) { int i; short n; g3s_uvl *uvl_val; ubyte *p = data; short_swap(wp(p)); while (w(p) != OP_EOF) { switch (w(p)) { case OP_DEFPOINTS: short_swap(wp(p + 2)); n = w(p+2); for (i = 0; i < n; i++) vms_vector_swap(vp((p + 4) + (i * sizeof(vms_vector)))); p += n*sizeof(struct vms_vector) + 4; break; case OP_DEFP_START: short_swap(wp(p + 2)); short_swap(wp(p + 4)); n = w(p+2); for (i = 0; i < n; i++) vms_vector_swap(vp((p + 8) + (i * sizeof(vms_vector)))); p += n*sizeof(struct vms_vector) + 8; break; case OP_FLATPOLY: short_swap(wp(p+2)); n = w(p+2); vms_vector_swap(vp(p + 4)); vms_vector_swap(vp(p + 16)); short_swap(wp(p+28)); for (i=0; i < n; i++) short_swap(wp(p + 30 + (i * 2))); p += 30 + ((n&~1)+1)*2; break; case OP_TMAPPOLY: short_swap(wp(p+2)); n = w(p+2); vms_vector_swap(vp(p + 4)); vms_vector_swap(vp(p + 16)); for (i=0;iu); fix_swap(&uvl_val->v); } short_swap(wp(p+28)); for (i=0;ip3_x > p->p3_z) cc |= CC_OFF_RIGHT; if (p->p3_y > p->p3_z) cc |= CC_OFF_TOP; if (p->p3_x < -p->p3_z) cc |= CC_OFF_LEFT; if (p->p3_y < -p->p3_z) cc |= CC_OFF_BOT; if (p->p3_z < 0) cc |= CC_BEHIND; return p->p3_codes = cc; } //rotates a point. returns codes. does not check if already rotated ubyte g3_rotate_point(g3s_point *dest,const vms_vector *src) { vms_vector tempv; vm_vec_sub(&tempv,src,&View_position); vm_vec_rotate(&dest->p3_vec,&tempv,&View_matrix); dest->p3_flags = 0; //no projected return g3_code_point(dest); } //checks for overflow & divides if ok, fillig in r //returns true if div is ok, else false int checkmuldiv(fix *r,fix a,fix b,fix c) { quadint q,qt; q.low=q.high=0; fixmulaccum(&q,a,b); qt = q; if (qt.high < 0) fixquadnegate(&qt); qt.high *= 2; if (qt.low > 0x7fff) qt.high++; if (qt.high >= c) return 0; else { *r = fixdivquadlong(q.low,q.high,c); return 1; } } //projects a point void g3_project_point(g3s_point *p) { #ifndef __powerc fix tx,ty; if (p->p3_flags & PF_PROJECTED || p->p3_codes & CC_BEHIND) return; if (checkmuldiv(&tx,p->p3_x,Canv_w2,p->p3_z) && checkmuldiv(&ty,p->p3_y,Canv_h2,p->p3_z)) { p->p3_sx = Canv_w2 + tx; p->p3_sy = Canv_h2 - ty; p->p3_flags |= PF_PROJECTED; } else p->p3_flags |= PF_OVERFLOW; #else double fz; if ((p->p3_flags & PF_PROJECTED) || (p->p3_codes & CC_BEHIND)) return; if ( p->p3_z <= 0 ) { p->p3_flags |= PF_OVERFLOW; return; } fz = f2fl(p->p3_z); p->p3_sx = fl2f(fCanv_w2 + (f2fl(p->p3_x)*fCanv_w2 / fz)); p->p3_sy = fl2f(fCanv_h2 - (f2fl(p->p3_y)*fCanv_h2 / fz)); p->p3_flags |= PF_PROJECTED; #endif } //from a 2d point, compute the vector through that point void g3_point_2_vec(vms_vector *v,short sx,short sy) { vms_vector tempv; vms_matrix tempm; tempv.x = fixmuldiv(fixdiv((sx<<16) - Canv_w2,Canv_w2),Matrix_scale.z,Matrix_scale.x); tempv.y = -fixmuldiv(fixdiv((sy<<16) - Canv_h2,Canv_h2),Matrix_scale.z,Matrix_scale.y); tempv.z = f1_0; vm_vec_normalize(&tempv); vm_copy_transpose_matrix(&tempm,&Unscaled_matrix); vm_vec_rotate(v,&tempv,&tempm); } //delta rotation functions vms_vector *g3_rotate_delta_x(vms_vector *dest,fix dx) { dest->x = fixmul(View_matrix.rvec.x,dx); dest->y = fixmul(View_matrix.uvec.x,dx); dest->z = fixmul(View_matrix.fvec.x,dx); return dest; } vms_vector *g3_rotate_delta_y(vms_vector *dest,fix dy) { dest->x = fixmul(View_matrix.rvec.y,dy); dest->y = fixmul(View_matrix.uvec.y,dy); dest->z = fixmul(View_matrix.fvec.y,dy); return dest; } vms_vector *g3_rotate_delta_z(vms_vector *dest,fix dz) { dest->x = fixmul(View_matrix.rvec.z,dz); dest->y = fixmul(View_matrix.uvec.z,dz); dest->z = fixmul(View_matrix.fvec.z,dz); return dest; } vms_vector *g3_rotate_delta_vec(vms_vector *dest,vms_vector *src) { return vm_vec_rotate(dest,src,&View_matrix); } ubyte g3_add_delta_vec(g3s_point *dest,g3s_point *src,vms_vector *deltav) { vm_vec_add(&dest->p3_vec,&src->p3_vec,deltav); dest->p3_flags = 0; //not projected return g3_code_point(dest); } //calculate the depth of a point - returns the z coord of the rotated point fix g3_calc_point_depth(vms_vector *pnt) { quadint q; q.low=q.high=0; fixmulaccum(&q,(pnt->x - View_position.x),View_matrix.fvec.x); fixmulaccum(&q,(pnt->y - View_position.y),View_matrix.fvec.y); fixmulaccum(&q,(pnt->z - View_position.z),View_matrix.fvec.z); return fixquadadjust(&q); } dxx-rebirth-0.58.1-d1x/3d/rod.c000066400000000000000000000122111217717257200160050ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Rod routines * */ #include "3d.h" #include "globvars.h" #include "fix.h" grs_point blob_vertices[4]; g3s_point rod_points[4]; g3s_point *rod_point_list[] = {&rod_points[0],&rod_points[1],&rod_points[2],&rod_points[3]}; g3s_uvl uvl_list[4] = { { 0x0200,0x0200,0 }, { 0xfe00,0x0200,0 }, { 0xfe00,0xfe00,0 }, { 0x0200,0xfe00,0 } }; g3s_lrgb lrgb_list[4] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; //compute the corners of a rod. fills in vertbuf. int calc_rod_corners(g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width) { vms_vector delta_vec,top,tempv,rod_norm; ubyte codes_and; int i; //compute vector from one point to other, do cross product with vector //from eye to get perpendiclar vm_vec_sub(&delta_vec,&bot_point->p3_vec,&top_point->p3_vec); //unscale for aspect delta_vec.x = fixdiv(delta_vec.x,Matrix_scale.x); delta_vec.y = fixdiv(delta_vec.y,Matrix_scale.y); //calc perp vector //do lots of normalizing to prevent overflowing. When this code works, //it should be optimized vm_vec_normalize(&delta_vec); vm_vec_copy_normalize(&top,&top_point->p3_vec); vm_vec_cross(&rod_norm,&delta_vec,&top); vm_vec_normalize(&rod_norm); //scale for aspect rod_norm.x = fixmul(rod_norm.x,Matrix_scale.x); rod_norm.y = fixmul(rod_norm.y,Matrix_scale.y); //now we have the usable edge. generate four points //top points vm_vec_copy_scale(&tempv,&rod_norm,top_width); tempv.z = 0; vm_vec_add(&rod_points[0].p3_vec,&top_point->p3_vec,&tempv); vm_vec_sub(&rod_points[1].p3_vec,&top_point->p3_vec,&tempv); vm_vec_copy_scale(&tempv,&rod_norm,bot_width); tempv.z = 0; vm_vec_sub(&rod_points[2].p3_vec,&bot_point->p3_vec,&tempv); vm_vec_add(&rod_points[3].p3_vec,&bot_point->p3_vec,&tempv); //now code the four points for (i=0,codes_and=0xff;i<4;i++) codes_and &= g3_code_point(&rod_points[i]); if (codes_and) return 1; //1 means off screen //clear flags for new points (not projected) for (i=0;i<4;i++) rod_points[i].p3_flags = 0; return 0; } //draw a polygon that is always facing you //returns 1 if off screen, 0 if drew bool g3_draw_rod_flat(g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width) { if (calc_rod_corners(bot_point,bot_width,top_point,top_width)) return 0; return g3_draw_poly(4,rod_point_list); } //draw a bitmap object that is always facing you //returns 1 if off screen, 0 if drew bool g3_draw_rod_tmap(grs_bitmap *bitmap,g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width,g3s_lrgb light) { if (calc_rod_corners(bot_point,bot_width,top_point,top_width)) return 0; uvl_list[0].l = uvl_list[1].l = uvl_list[2].l = uvl_list[3].l = (light.r+light.g+light.b)/3; lrgb_list[0].r = lrgb_list[1].r = lrgb_list[2].r = lrgb_list[3].r = light.r; lrgb_list[0].g = lrgb_list[1].g = lrgb_list[2].g = lrgb_list[3].g = light.g; lrgb_list[0].b = lrgb_list[1].b = lrgb_list[2].b = lrgb_list[3].b = light.b; return g3_draw_tmap(4,rod_point_list,uvl_list,lrgb_list,bitmap); } #ifndef __powerc int checkmuldiv(fix *r,fix a,fix b,fix c); #endif #ifndef OGL //draws a bitmap with the specified 3d width & height //returns 1 if off screen, 0 if drew bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm) { #ifndef __powerc g3s_point pnt; fix t,w,h; if (g3_rotate_point(&pnt,pos) & CC_BEHIND) return 1; g3_project_point(&pnt); if (pnt.p3_flags & PF_OVERFLOW) return 1; if (checkmuldiv(&t,width,Canv_w2,pnt.p3_z)) w = fixmul(t,Matrix_scale.x); else return 1; if (checkmuldiv(&t,height,Canv_h2,pnt.p3_z)) h = fixmul(t,Matrix_scale.y); else return 1; blob_vertices[0].x = pnt.p3_sx - w; blob_vertices[0].y = blob_vertices[1].y = pnt.p3_sy - h; blob_vertices[1].x = blob_vertices[2].x = pnt.p3_sx + w; blob_vertices[2].y = pnt.p3_sy + h; scale_bitmap(bm,blob_vertices,0); return 0; #else g3s_point pnt; fix w,h; double fz; if (g3_rotate_point(&pnt,pos) & CC_BEHIND) return 1; g3_project_point(&pnt); if (pnt.p3_flags & PF_OVERFLOW) return 1; if (pnt.p3_z == 0) return 1; fz = f2fl(pnt.p3_z); w = fixmul(fl2f(((f2fl(width)*fCanv_w2) / fz)), Matrix_scale.x); h = fixmul(fl2f(((f2fl(height)*fCanv_h2) / fz)), Matrix_scale.y); blob_vertices[0].x = pnt.p3_sx - w; blob_vertices[0].y = blob_vertices[1].y = pnt.p3_sy - h; blob_vertices[1].x = blob_vertices[2].x = pnt.p3_sx + w; blob_vertices[2].y = pnt.p3_sy + h; scale_bitmap(bm, blob_vertices, 0); return 0; #endif } #endif dxx-rebirth-0.58.1-d1x/3d/setup.c000066400000000000000000000037111217717257200163660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Setup for 3d library * */ #include #include "dxxerror.h" #include "3d.h" #include "globvars.h" #include "clipper.h" //#include "div0.h" #ifdef OGL #include "ogl_init.h" #else #include "texmap.h" // for init_interface_vars_to_assembler() #endif //start the frame void g3_start_frame(void) { fix s; //set int w,h & fixed-point w,h/2 Canv_w2 = (Canvas_width = grd_curcanv->cv_bitmap.bm_w)<<15; Canv_h2 = (Canvas_height = grd_curcanv->cv_bitmap.bm_h)<<15; #ifdef __powerc fCanv_w2 = f2fl((Canvas_width = grd_curcanv->cv_bitmap.bm_w)<<15); fCanv_h2 = f2fl((Canvas_height = grd_curcanv->cv_bitmap.bm_h)<<15); #endif //compute aspect ratio for this canvas s = fixmuldiv(grd_curscreen->sc_aspect,Canvas_height,Canvas_width); if (s <= f1_0) { //scale x Window_scale.x = s; Window_scale.y = f1_0; } else { Window_scale.y = fixdiv(f1_0,s); Window_scale.x = f1_0; } Window_scale.z = f1_0; //always 1 init_free_points(); #ifdef OGL ogl_start_frame(); #else init_interface_vars_to_assembler(); //for the texture-mapper #endif } //this doesn't do anything, but is here for completeness void g3_end_frame(void) { #ifdef OGL ogl_end_frame(); #endif // Assert(free_point_num==0); free_point_num = 0; } dxx-rebirth-0.58.1-d1x/CHANGELOG.txt000066400000000000000000010002131217717257200165770ustar00rootroot00000000000000D1X-Rebirth Changelog 20130611 -------- main/wall.c: Made wall_damage() and blast_blastable_wall() similar to D2X-Rebirth code base. Also fixing regression introduced in a4068234b4 causing blast_blastable_wall() being called multiple times and causing high damage main/titles.c: Fixed briefing_screens array for Descent 1 Shareware main/menu.c: Changed message regarding VSync and Multisampling indicating not all OSes need a restart to apply (mysteries of SDL) main/laser.c: Consider FrameTime overhead when calculating time to allow next weapon fire. Should work perfectly as long as FPS >= Shots-per-second 20130610 -------- misc/hmp.c: Made hmp code actually read tempo. Due to missing documentation of the format I can only guess it's a 4 bit int 20130422 -------- main/net_udp.c: In restricted game mode check for player callsign and sockaddr at the same time; Clear Netgame struct each time player enters a new IP in manual join menu arch/sdl/rbaudio.c: Added a lot of status messages for RBA code shown with -verbose, hopefully making it easier for users to track down problems and made all RBA messages start with RBAudio prefix 20130418 -------- main/lighting.c, main/render.c: Removed light_frame_count due to being unnecessary since lighting is now time-based and messed up deletion of dynamic light main/render.c: Due to additive blending, transparent sprites will become invivible in font of white surfaces (lamps). Fix that with a little desaturation main/net_udp.h: Made UPID_GAME_INFO_SIZE, UPID_GAME_INFO_LITE_SIZE and UPID_SEQUENCE_SIZE change if NETGAME_NAME_LEN, MISSION_NAME_LEN or CALLSIGN_LEN changes, fixes bug where joining games was not possible anymore due to recent change of MISSION_NAME_LEN main/multi.c: use const ubyte for multi_do_powcap_update() main/gauges.c: Adjusted SB_PRIMARY_W_BOX_RIGHT_L to fit perfectly 20130408 -------- main/gamecntl.c, main/gamerend.c, main/gauges.c, main/gauges.h: Added 4th alternative HUD mode for no HUD rendering, aka Immersion mode main/menu.c, main/playsave.c, main/playsave.h, main/weapons.c: Added option to ignore cycling weapons that are not on autoselect list 20130406 -------- d1x-rebirth.xcodeproj/project.pbxproj, editor/ehostage.c, main/custom.c: Updated Xcode project, changed references to error.h to dxxerror.h, since it was renamed .gitignore: Added .gitignore 20130405 -------- SConstruct: For the assembler build, make sure platform_settings is accessed from self, likely preventing a compiling error SConstruct: Changes towards building using SCons on Mac OS X 20130122 -------- README.RPi, SConstruct, arch/ogl/gr.c: Support for Raspberry Pi - patch by derhass main/controls.c: Increased ship wiggle from 20FPS- to 30FPS-base as I think this more representy the 486 play style - feels way more natural to me, too 20130119 -------- main/gamerend.c, main/menu.c, main/multi.c, main/multi.h, main/net_udp.c, main/playsave.c, main/playsave.h: Added Rankings functionality like in D2X-Rebirth while still utilizing eff file from original D1X source main/multi.c, main/multi.h: Decrease personal score when killing multi buddy and don't increment towards kill goal 20130117 -------- main/render.c: Fix click-selection in the editor for OpenGL implementations that insist on point blending 20130112 -------- arch/carbon/conf.h: Used new D1XMAJORi / D1XMINORi / D1XMICROi version constants for Mac main/inferno.h, main/mission.c, main/mission.h: Increased the maximum number of levels and secret levels per mission to 127 each, using MALLOC'd arrays; defined 'd_fname' type (mainly for my pointers to arrays of 13 character filenames, but could be convenient elsewhere) arch/carbon/messagebox.c, arch/win32/messagebox.c: If there's a messagebox to show on exit, and we *were* in fullscreen, don't try to toggle fullscreen and crash 20130108 -------- main/gamerend.c, main/multi.c, net_udp.c: Fixed some minor HUD-text related issues: For team assignment messages, joining player name would appear; team color assignment in netgame info screen could be wrong due to wrong syntax handling; when rewrapping text messages to specific player, game would not add space behind colon main/kmatrix.c: Defer free of kmatrix data until window is fully gone - patch by Kp main/kconfig.c: Added default keys for weapon cycling similar to Descent 2 and reverted default reverse key to Z as default as more convinient for the QUERTY keyboard layout main/inferno.c: Disable fullscreen toggling via ALT+ENTER if Game_wind is on top so toggling cannot be done accidentially ingame arch/sdl/mouse.c, d1x.ini, include/args.h, main/inferno.c, misc/args.c: Added option to hide mouse cursor (without disabling the mouse completely) SConstruct: Patch by A Future Pilot to hopefully fix bug which prevented building source within MinGW if Visual Studio installed arch/ogl/ogl.c: Changed additive color blending func to GL_ONE, GL_ONE - patch by derhass 20130103 -------- main/net_udp.c: Centralized UDP Broadcast function for IPv4 and IPv6 calls - patch by Kp editor/med.c: Deleted unnecessary drop-to-shell feature; commented out unused ReadLispMacro - patches by Kp 2d/font.c, include/ogl_init.h: Moved pow2ize declaration to ogl_init.h - patch by Kp main/bmread.c, main/hostage.c, main/piggy.h: Moved remove_char declaration to piggy.h - patch by Kp main/multi.h, main/net_udp.c: Moved multi_* declarations to multi.h - patch by Kp maths/rand.c: Included maths.h in rand.c to get d_rand prototype - patch by Kp arch/include/joy.h, arch/sdl/event.c, arch/sdl/joy.c: Moved joy_*_handler declarations to joy.h - patch by Kp editor/group.c, editor/medwall.c, editor/segment.c, main/gameseg.h, main/wall.h: Declared wall_close_door_num in wall.h; Declared validate_segment_side in gameseg.h - patches by Kp include/3d.h, main/gameseq.h: Removed redundant/obsolete declarations - patch by Kp main/kconfig.h: Moved large control_info arrays to end - patch by Kp medrobot.c: medrobot: avoid needless name copy - patch by Kp editor/centers.c, main/gamecntl.c: Fixed argument specifier mismatches flagged by -Wformat - patch by Kp arch/ogl/gr.c, main/game.c: Moved screenshot message formating to HUD_init_message - patch by Kp (and me for non-OGL code ;)) main/automap.c, main/credits.c, main/gamerend.c, main/gauges.c, main/hud.c, main/kmatrix.c, main/menu.c, main/newmenu.c, main/scores.c: Converted gr_printf to gr_string where needed - patch by Kp editor/medrobot.c, main/endlevel.c, main/gamecntl.c, main/powerup.c, main/wall.c, main/weapon.c, ui/file.c: Added dummy "%s" to prevent formatting untrusted literals - patch by Kp main/hud.c: Removed obsolete HUD cleaning code - patch by Kp editor/info.c: Use proper width in format specifier - patch by Kp 20121102 -------- arch/include/key.h, arch/sdl/key.c, main/kconfig.c: Made key_properties readable in other files; Eliminated key_text variable; Marked unicode_frame_buffer as extern in header - patches by Kp arch/ogl/gr.c, arch/ogl/ogl.c, include/gr.h: Removed 'new' from prototypes; Declared ogl_do_palfx(), ogl_close_pixel_buffers(), ogl_init_pixel_buffers() in gr.h - patches by Kp include/maths.h, include/texmap.h, include/ui.h, main/object.c, maths/fixc.c, maths/tables.c, texmap/ntmap.c, ui/dialog.c, ui/icon.c: Moved ui_draw_frame(), ui_draw_shad(), draw_tmap_flat(), math tables externs to headers - patches by Kp 3d/clipper.c, 3d/draw.c, editor/meddraw.c, include/3d.h, main/automap.c, main/render.c: in g3s_codes renamed or,and to uor,uand - patch by Kp main/object.h: use struct type explicitly - patch by Kp include/error.h: Renamed __format to __attribute_gcc_format due to possible C++ conflict; allow arguments - patch by Kp include/console.h, main/console.c: Marked con_printf fmt as const, Increased console lines from 512 to 2048; Marked console private entries as static - patches by Kp 2d/font.c: Fixed test for font magic number; Consolidated grs_font_read() - patches by Kp main/menu.c, main/multi.h, main/net_udp.c: Moved vers_id.h inclusion to where it is needed - patch by Kp 2d/bitmap.c: Include bitmap.h - patch by Kp 2d/bitblt.c, include/rle.h: Move declaration of gr_rle_expand_scanline_generic() to rle.h - patch by Kp 20121031 -------- main/hostage.h, include/u_mem.h: Fixed inconsistency in hostage_rescue() definition and revoked recent patch for u_mem.h due to infinite loops in mem.c caused by this 20120903 -------- arch/sdl/jukebox.c, main/gauges.c: Avoid some unnecessary strlen's - (slightly changed) patch by Kp misc/args.c: Made FindArg static - patch by Kp 20120902 -------- include/u_mem.h: Compile out memory checker if not enabled - patch by Kp 20120901 -------- main/vers_id.h: Fixed incorrect patch merge introduced in the last commit main/fireball.c, main/laser.c: Removed Assert in create_smart_children() which has been taken from D2X code but does not apply for D1X and only will let the Assert fail main/laser.c, main/laser.h, main/object.c, main/object.h, main/powerup.h: Use enum for object types, powerup types, weapon types 20120728 -------- SConstruct, main/vers_id.h: Some Sconstruct lovin': Respect LDFLAGS; Made D1XMAJORi/MINORi/MICROi compile time constants; Do not pass CFLAGS to CXX; Mark some more warnings as errors - patches by Kp 20120724 -------- main/bmread.c: No calling piggy_dump_all() when EDITOR is defined, it causes a failed Assert and causes it to exit when the PC Shareware descent.pig is used English.lproj/InfoPlist.strings, d1x-Info.plist, d1x-rebirth.xcodeproj/project.pbxproj, d1xgl-Info.plist: Increment version number for Mac files (should have committed this ages ago) include/strutil.h, main/collide.c, main/dumpmine.c, ui/gadget.c, ui/radio.c: Fix warnings (add d_splitpath prototype, no checking ubyte 'id' is < 0, fix say_totals prototype, include d_strdup prototype for radio.c and make sure that 'text' gets freed) main/polyobj.c: Don't draw objects with a modelnum of -1, improving stability when a third party mission is played with shareware data 20120723 -------- 2d/font.c,, 2d/pcx.c, 3d/points.c, arch/include/jukebox.h, arch/sdl/jukebox.c, iff/iff.c, include/3d.h, include/error.h, include/gr.h, include/iff.h, include/pcx.h, include/physfsx.h, include/vecmat.h, main/ai.c, main/config.c, main/dumpmine.c, main/fvi.c, main/fvi.h, main/gamefont.c, main/gamesave.c, main/gamesave.h, main/gameseg.c, main/gameseg.h, main/kconfig.c, main/kconfig.h, main/menu.c, main/multi.c, main/multi.h, main/newdemo.c, main/newmenu.c, main/newmenu.h, maths/vecmat.c, misc/error.c, misc/physfsx.c: Redefined lotsa variables, functions and parameters as const and/or static - patch by Kp 20120618 -------- main/gamerend.c, main/multi.c: removed temp_string buffer for ingame message inputs preventing the string from being messed up if containing special characters main/game.c, main/gameseq.c, main/multi.c, main/multi.h, main/player.h, main/powerup.c: Introduced INITIAL_ENERGY and INITIAL_SHIELDS defines from d2x and on that way added handicap feature for multiplayer as well; incremented multi proto version 20120610 -------- arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, main/songs.c, main/songs.h: added songs_play_file() to play any song depending on filename-extension as a more streamlined approach to handle all different kinds of formats; also used for jukebox to make it independent from SDL_mixer; cleaned up supported filename extenstions 20120608 -------- main/kconfig.c: Switching keyboard sensitivity function from variable increase to variable offset, making the ship more responsive in higher settings math/vecmat.c: in vms_matrix_from_quaternion put the definition of tmp1 and tmp2 variables at the beginning of the functions because i was a baaaad boy 20120601 -------- main/kconfig.c, main/kconfig.h, main/menu.c, main/playsave.c, main/playsave.h: Introduced sensitivity sliders for keyboard which cause movement increase the longer the designated key is pressed main/gauges.c, main/menu.c, main/net_udp.c, main/songs.c, misc/physfsx.c: use size of output buffer for snprintf; on the way changed rebirth-specific song file to dxx-r.sng to respect hog 8+3 file convention editor/med.c, misc/physfsx.c: changed extension for archive (addon) content from zip to dxa - still a zip-file but renamed to not accidentially add user generated backups and possibly mess things up med/file.c: renamed forgotten stricmp to d_stricmp to make editor compile again 20120527 -------- editor/med.c, main/game.c, main/game.h, main/gamerend.c, main/menu.c: Removed remnants of the old and obsolete VR implementation main/laser.c: removed weapon_rate_scale() which should be obsolete due to other optimizations in network code; Removed Laser_offset hack 20120526 -------- main/collide.c: Fit player/player collisions to not take damage from bump while remote player has possibly not aligned to the collision, yet; Added FORCE_DAMAGE_THRESHOLD for minimum force damage to receive from object bumps to not simply take damage from touching objects main/net_udp.c: Fixed one more copy/paste issue causeing positional updates relayed to possibly disconnected players include/vecmat.h, main/gameseg.c, main/multi.h, main/net_udp.c, main/net_udp.h, main/object.h, maths/vecmat.c: Optimization for quaternion structure: Stuffed orientation in shorts and removed figure out segnum by position - saving 10 bytes for each positional update in Multiplayer; Also removed render_type from pdata to save yet another byte main/titles.c: fixed possible buffer overflow in load_screen_text() 20120525 -------- main/cntrlcen.c, main/game.c, main/switch.c: Cancel out do_controlcen_dead_frame() when not playing and only check triggers for playing players for further host-authority stuff; Made GameProcessFrame not cause endless loop by closing kmatrix over and over again due to game_leave_menus(); Also only close menus when level ends and when we die only the automap will close - otherwise menus can stay (user request) 20120524 -------- main/gameseq.c, main/multi.c: in StartLevel() only call disable_matcens() and clear_transient_objects() in Singleplayer to keep consistency with remote clients 20120521 -------- main/state.c: now properly initialize all other parts of the new/old player object when restoring a coop savestate include/vecmat.h, main/gameseg.c, main/multi.c, main/multi.h, main/net_udp.c, main/net_udp.h, main/object.h, main/playsave.c, maths/vecmat.c: Introduced quaternion functions to replace vector matrix where size matters - created by Florian Feucht; Added option for pdata packets based on quaternion in Multiplayer game; Removed PF_LEVELLING from new player objects to prevent jittering in player banking 20120519 -------- arch/ogl/gr.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, editor/autosave.c, editor/func.c, include/strutil.h, main/bmread.c, main/gamecntl.c, main/gamesave.c, main/hash.c, main/hud.c, main/menu.c, main/mission.c, main/multi.c, main/net_udp.c, main/newmenu.c, main/piggy.c, main/playsave.c, main/scores.c, main/songs.c, main/text.c, main/titles.c, misc/args.c, misc/physfsx.c, misc/strutil.c, texmap/scanline.c, ui/file.c: using our own functions for stricmp, strnicmp, strlwr, strupr, strrev with a d_ prefix for all platforms for consistency editor/kmine.c, editor/mine.c, include/strutil.h, include/u_mem.h, main/gamesave.c, mem/mem.c, misc/strutil.c: using our own functions for strdup and _splitpath with the d_ prefix for all platforms for consistency 20120518 -------- main/state.c: fixed incorrect canvase for opengl-scaled savestate thumbnail; rebuild free objects after restoring and remapping the coop players 20120516 -------- main/game.c: In Multiplayer when taking damage, the game will only leave menus when shield drop below 5 main/net_udp.c: when updating game info also check for player connected status in case we send to everyone main/gamecntl.c, main/object.c: allow PAUSE key during death sequence to pause or view multiplayer game stats; Also reset hostages_on_board when ship blows up so pause menu during death sequence will show 0 hostages soon as the ship explodes; fixed crash for slew_init by removing old numlock hack 20120515 -------- main/net_udp.c: Do not send endlevel packets to disconnected (but still saved) clients; Do not allow ports below 1024; More verbosity for udp_open_socket() 20120514 -------- 2d/disc.c, SConstruct, editor/medmisc.c, include/gr.h, include/internal.h, main/menu.c, main/net_udp.c, main/playsave.c, main/state.c, misc/hmp.c, misc/physfsx.c: Fixed some non-critical compiler warnings; Now compiling with -std=c99 -pedantic and fixed warnings (except for editor build) caused by this 2d/bitblt.c, 2d/pixel.c, arch/sdl/digi_mixer.c, main/gauges.c, main/menu.c: Made inline functions static include/gr.h, main/ai.c, main/aipath.c, main/automap.c, main/cntrlcen.c, main/fuelcen.c, main/game.c, main/game.h, main/gamecntl.c, main/gamerend.c, main/laser.c, main/mglobal.c, main/object.c, main/render.c, main/texmerge.c, main/wall.c: Renamed FixedStepCalc() to cald_d_tick() and FixedStep became d_tick_step; Also ther eonly is a 50ms-timer used to d_tick_step as it was the only one used so far; Replaced FrameCount with d_tick_count which only increments by 50ms-timer used in calc_d_tick() - that now scales timed actions for certain functions properly and makes AI work FPS-independent without any hacks in that regard main/multi.c: During kmatrix bring up Game_wind againso the host can still follow the game - becomes necessary later with host-authority functions 20120510 -------- main/multi.h, main/state.c: Reuse pre-defined player objects when loading coop savestate to revent messup when player amount or orders change in a certain way main/menu.c, main/playsave.c, main/playsave.h, main/weapon.c: Wrote seperate function for weapon autocycling that also cycles through non-autoselect weapons; Added option to not autoselect weapon when firing; On the way, smoothed the menu text in misc menu a bit net_udp.h: Reduced timeout from 10 to 5 seconds RELEASE-NOTES.txt, SConstruct, arch/carbon/conf.h, main/multi.h: Incremented version to 0.57.3; Added Release notes 20120509 -------- main/laser.c, main/multi.h: Added more versatility in picking targets for the creation of smart blobs - especially for Multiplayer; cleaned that code a bit; made dodging of homing projectiles a little easier 20120430 -------- main/net_udp.c: fixed copy/paste mistake 20120427 -------- main/inferno.c, main/multi.c, main/multi.h: Similar to Network_new_game introduced imulti_new_game to exclusivly use in multi.c to execute stuff in new level only when starting a new game - for example resetting player ship inventory which is not supposed to happen on each level; Removed long obsolete control_invul_time varible 20120424 -------- main/gauges.c: little reorganization for draw_hud(): draw multiplayer names first, reticle last to prevent anything being drawn over by floating names and reticle not messed by anything else 20120423 -------- main/multi.c, main/multi.h, main/net_udp.c: fixed improper player disconnecting which might have been caused by endlevel packet 20120418 -------- main/gameseq.c, main/gameseq.h, main/gauges.c, main/multi.c, main/net_udp.c, main/state.c: Removed usage of 'oldmaxnet' variable when switching between coop and other game modes which would not be correctly set when coop mode is loaded from a netgame profile; Removed 'MaxNumNetPlayers' variable as already replaced by Netgame.max_numplayers 20120417 -------- main/gameseq.c: Allow level progressing if playing the builtin mission with EDITOR compiled - only exit if Current_level_num is 0 editor/med.c: Reset the player object for the editor, since demo playback mucks it up main/render.c: Skip rendering of OBJ_NONE objects to avoid a failed Assert (can happen when playing a demo then going to the editor) main/newdemo.c: Set object lifeleft to IMMORTAL_TIME if the byte read in demo playback is -1. This allows the objects to stay when playing a demo, going to the editor then playing the game from the editor main/newdemo.c: Call free_mission() if a demo is corrupt, so the editor doesn't load a corrupt level editor/group.c, editor/kgame.c, editor/khelp.c, editor/kmine.c, editor/macro.c, editor/med.c, editor/medwall.c, editor/mine.c, include/ui.h, ui/file.c, ui/keypad.c, ui/menubar.c, ui/message.c: Rename MessageBox to ui_messagebox to avoid a conflict with Windows' MessageBox main/newdemo.c, main/object.c, main/object.h: Call new obj_relink_all after playing a demo, so the editor is (hopefully) never faced with poorly linked objects and hence crashes 20120416 -------- main/gameseq.c, main/multi.c, main/multi.h: fixed two bugs caused by recent Multiplayer cleanup: Set more player-death-related veriables outside of dead_player_end() when creating new ship as not covered in subfunction is Palyer_is_dead is not true; also init my own inventory properly in multi_prep_level to get our inventory straight after receiving netgame information editor/data/med.mnu, editor/med.c, editor/medmisc.c, main/slew.c, ui/ui.c: Make movement in the editor's game screen use the player controls, make that movement more like the automap and resolve some likely conflicting key commands editor/centers.c, editor/eswitch.c, editor/med.c, editor/medrobot.c, editor/medwall.c, main/game.c, main/gameseq.c: Avoid crashes when clicking on close box with a center, switch, object or wall editing dialog open; also when playing a level, going to the editor, going back to the game then dying editor/eglobal.c, editor/med.c, main/game.c, main/gamesave.c, main/menu.c, main/mission.c, main/mission.h: Make a new mission when making a new mine to avoid a crash when testing it straight from the editor and winning, only create a new mine if a mission isn't loaded, if it thinks it needs to use Cursegp to fix the player object make sure Cursegp is initialised, remove key command for ToggleDrawAllSegments since add segment now has ctrl-A 20120415 -------- main/multi.c, main/multi.h, main/net_udp.c: When possibly sending player positions prior to firing, do that before messing multibuf; Added more strict sanity checks for outgoing and incoming multi packets; Moved some general game stuff from net_udp_init() to multi_new_game() editor/meddraw.c: Set edge_list_size to Num_segments*12 to avoid crashes in the editor with certain third party levels 2d/gpixel.c, arch/ogl/gr.c, editor/meddraw.c, include/ogl_init.h, main/multi.c, main/render.c: Clicking on mine elements in the editor now works in ogl main/bmread.c, main/game.c, main/gameseq.c, main/gameseq.h, main/gauges.c, main/kmatrix.c, main/multi.c, main/multi.h, main/net_udp.c, main/state.c: Further Multiplayer cleanup: moved gobal variable resets from multi_new_game() to proper function calls; added pnum variable to init_player_stats_game() and init_player_stats_new_ship() so these can be set for each player when starting match; added multi_new_level() calls when setting up game as well when trying to join game; cleaned multi_reset_stuff() from variable resetting that happen in general game code; when being dumped from game, made sure no packets are sent during messagebox dispaly; replaced MAX_NUM_NET_PLAYERS by MAX_PLAYERS as it's the same definition misc/hmp.c: Addition for last change in hmp_reset(): execute midiOutShortMsg() even if midiOutPrepareHeader() fails as not related to SysEx part main/titles.c: made -notitles suppress show_order_form() as well 2d/bitblt.c, main/render.c: Fixed set but unused variables in OGL build 20120414 -------- main/gamesave.c: Fix crash when loading a level in the editor editor/segment.c, include/editor/editor.h, main/gamesave.c: Set Gamesave_current_version to correct version when making a new mine, move create_new_mine to gamesave.c main/gamesave.c: Don't bother generating a game text file (.txm) every time a level is loaded, even if the EDITOR is compiled. Just when a level is saved editor/med.c, main/game.c, main/gamecntl.c: Delete-E while playing a level now works properly - it closes Game_wind and sets Cursegp if necessary when going to the editor editor/med.c, main/dumpmine.c, main/gamecntl.c, ui/ui.c: Fix bugs switching between game and editor and back: make sure ModeFlag is set to 0 before it has any chance to show an alert message, fixing a crash; allow OBJ_NONE in Assert; make Game_wind invisible when loading editor in case we show an alert; call mouse_flush() in ui_init() to fix mouse issues editor/med.c: Set the correct palette for the editor 20120412 -------- main/collide.c, main/gameseq.c, main/multi.c, main/multi.h, main/net_udp.c: Fixed some Multiplayer bugs: Reactor invulnerable time did not checked for hours spent in level so reactor would become invulnerable again after 60 minutes; Fixed the fix (heh) for misordered explode/reappear packets; Reset Player_eggs_dropped when initializing new ship so eggs are properly dropped when player disconnects two times without respawning; Cleaned player disconnecting a little bit and made code more straightforward main/menu.c, misc/hmp.c: Removed redundant call of songs_stop_all() when starting credits; Added failsafe for loop in case MHDR_DONE flag is not properly set by MIDI device; Added more verbosity for hmp_reset() 20120411 -------- editor/ehostage.c, editor/medrobot.c, ui/file.c, ui/inputbox.c, ui/keypress.c, ui/listbox.c, ui/message.c, ui/uidraw.c: Draw the object rotation velocity, file browser and MessageBox dialogs properly ui/file.c: Fix a crash when going into a directory with no files in the editor file browser, clicking on listboxes for same sets inputbox correctly 20120409 -------- main/state.c: in software rendering scale savestate thumbnail to correct size editor/autosave.c, editor/info.c, editor/med.c, editor/objpage.c, editor/texpage.c, include/ui.h, ui/keypad.c, ui/uidraw.c: Get the clock, 'keypad' info, texture choosing page and object choosing page to draw (latter two just show black squares for ogl) arch/sdl/window.c, ui/menubar.c: Fix a nasty bug where pressing 'Alt' to explore the editor menubar would split the window stack in two, rendering the editor unresponsive 2d/bitblt.c, 2d/box.c, 2d/font.c, arch/ogl/gr.c, editor/med.c, ui/dialog.c, ui/uidraw.c, ui/userbox.c: Fix all remaining known editor drawing issues. In ogl: get the texture previews to draw, get userbox borders to draw in the right location, properly underline characters in the menus, draw all the borders properly (i.e. no gap), no scaling fonts. Software render: draw userbox borders again. Both: clear the whole status bar, clear to the right edge of the screen. main/newmenu.c: No setting the screen mode when calling a newmenu function, so if it shows the 'Save Mine' messagebox in the editor, it won't change the screen resolution and trash everything. (If this causes problems, we can make it use the MessageBox if it's still in the editor, nm_messagebox otherwise) 2d/rect.c, editor/info.c, editor/med.c, include/ui.h, main/inferno.c, ui/dialog.c, ui/menubar.c: Editor exits cleanly when clicking the close box, no more redundant gr_uscanline call in gl_urect for ogl (an initial attempt to fix the previous bug) 2d/rect.c: Fix unused variable warning in last commit 20120408 -------- main/mission.c, main/mission.h, main/titles.c: added specification for Descent: Destination Saturn briefing screen to properly show briefings; added different briefing structure for Descent 1 Shareware which has a slightly different order of the usual briefings main/collide.c: plasma fire can ignite bombs which are dropped while firing. to compensate added a timed check where at least one projectile must be older than 200ms to trigger a possible collision. this fixes this issue if the player is moving away from the bomb 20120407 -------- main/fireball.c: made choose_drop_segment more similar to D2X-Rebirth and let fallback correctly check for reactor segment 2d/font.c: made code more similar to D2X-Rebirth by introducing open_font which allows to keep track of font_data and free it properly 2d/font.c, misc/strutil.c: removed redundant definitions of FILENAME_LEN main/multi.c, main/multi.h: fixed glitch when reappear and explode packets are misordered, rendering player invisible main/gauges.c: record shields if player is invulnerable to get proper shield display in demo playback if player respawns with invulnerability on 20120405 -------- include/maths.h, main/fvi.c, maths/fixc.c: Introduced fixmul64 returning fix64 type to use with check_point_to_face() and prevent fix overflow with very large faces; on the way cleaned up NO_FIX_INLINE remnants and replaced QLONG with fix64 20120331 -------- d1x-rebirth.xcodeproj/project.pbxproj, 2d/font.c: Make sure the ogl font code recognises the editor font is fixed width, fixing a crash; take the plunge and make D1X Rebirth compile with editor for Mac OpenGL build (won't work yet) editor/med.c, editor/meddraw.c, editor/medmisc.c, include/editor/editor.h, main/render.c: Make all drawing in the editor single buffered, since the whole screen is double buffered. Fixes crash - but only shows a black screen and the menu for ogl editor/med.c, editor/meddraw.c, editor/medmisc.c, ui/button.c, ui/checkbox.c, ui/dialog.c, ui/file.c, ui/icon.c, ui/inputbox.c, ui/listbox.c, ui/menubar.c, ui/radio.c, ui/scroll.c, ui/userbox.c: Make the main stuff (gadgets, two viewers) draw for the editor in ogl, still more tweaking required ui/dialog.c: Use correct coordinates for dialog border (still doesn't draw fully) editor/medmisc.c, ui/button.c, ui/checkbox.c, ui/icon.c, ui/inputbox.c, ui/listbox.c, ui/radio.c, ui/scroll.c, ui/userbox.c: Make the editor draw the same for the non-ogl build as the ogl build, since I just made it draw the grey background over everything in the last commit. If you want to see what it's *supposed* to look like, go to yesterday's commit :P 20120330 -------- 2d/font.c, include/gr.h: Make 2d/font.c more similar between d1x-rebirth and d2x-rebirth arch/include/event.h: Changed declaration of event_get_idle_second() from int32_t to fix since Windows does not know it without pstypes.h. Included maths.h for this but should now work flawlessly on all platforms 20120329 -------- main/multi.c, main/multi.h, main/net_udp.c, main/net_udp.h: Immediately relay pdata packets from clients to others which should reduce artificial delay; allow sending of pdata packet when firing if enough time has passed since last update; only answer full game info requests 2 times per second and lite info 8 times per second main/songs.c: Fixed Redbook playback which was not repeating the CD after finishing 20120328 -------- main/slew.c: Fix compile-time error when building without editor arch/sdl/jukebox.c, main/songs.c: Allow .flac to be a filename extension for sng file and jukebox main/state.c: properly disable cheats when loading a saved game so only cheats that were stored are re-enabled main/collide.c, main/physics.c: Fixed double wall-object-damage introduced 20111124 by applying more strict rules to wall-colliding and wall-scraping where latter now is player-exclusive main/net_udp.c: in netgame info screen some setting-descriptions were interchanged and displayed wrong toggles main/net_udp.c: Since the kicked message is shown after player is technically removed from the game we do not know hosts name anymore. Message changed accordingly main/multi.c, main/multi.h, main/newdemo.c, main/player.h: Allow a total of 32 different player ship textures and stored N_PLAYER_SHIP_TEXTURES in player.h main/config.c: Dynamically allocate line to read from descent.cfg and ensure a safe length main/gamesave.c, main/net_udp.c: Added forgotten D2 powerup capping code when starting level which hopefully fixes massive powerup loss 20120324 -------- arch/ogl/gr.c, arch/sdl/gr.c, ui/menubar.c: Draw the editor menubar properly - by drawing in response to EVENT_WINDOW_DRAW and initialising the screen canvas properly. The latter fixes a lot of other editor drawing issues as well 2d/bitmap.c, arch/include/window.h, arch/sdl/gr.c, arch/sdl/window.c, include/gr.h: Update the canvas data pointers for all windows after changing the screen mode, so the main menu draws properly after leaving the editor arch/include/event.h, editor/centers.c, editor/curves.c, editor/ehostage.c, editor/eswitch.c, editor/med.c, editor/meddraw.c, editor/medrobot.c, editor/medwall.c, ui/dialog.c, ui/userbox.c: Draw in response to EVENT_UI_DIALOG_DRAW, uncomment medlisp_update_screen call and use gr_box instead of gr_rect in some places. You can now see what you're doing! ui/gadget.c: Fix bug where pad buttons would disappear when clicking on them, after opening then closing a dialog 20120319 -------- editor/med.c, include/editor/editor.h, include/ui.h, main/gamecntl.c, main/gameseq.c, main/inferno.c, main/menu.c: The editor now falls back to the main event loop in inferno.c, File->Exit now works as intended and get closer to making the editor and game work together editor/med.c, main/endlevel.c, main/gamecntl.c, main/gamesave.c, main/inferno.c, main/inferno.h, main/menu.c, main/powerup.c, main/render.c, main/slew.c: Remove all remaining uses of Function_mode, checking for the existence of EditorWindow where necessary instead 20120318 -------- editor/med.c, editor/texpage.c, include/editor/editor.h, main/game.c: Do a bit of a tidy up for the editor, dump code from editor() within the loop into new editor_handler() editor/info.c, editor/med.c, editor/medmisc.c, editor/objpage.c, editor/texpage.c, include/editor/objpage.h, include/editor/texpage.h, include/ui.h, ui/userbox.c: Make editor_handler into a proper callback, iron some problems out. Seems to draw a different bunch of stuff now (still erroneous) SConstruct, arch/include/event.h, arch/include/mouse.h, arch/sdl/event.c, d1x-rebirth.xcodeproj/project.pbxproj, editor/info.c, editor/macro.c, editor/med.c, editor/meddraw.c, editor/medmisc.c, include/ui.h, ui/button.c, ui/checkbox.c, ui/dialog.c, ui/file.c, ui/icon.c, ui/inputbox.c, ui/listbox.c, ui/menubar.c, ui/mouse.c, ui/radio.c, ui/scroll.c, ui/ui.c, ui/userbox.c: Remove redundant ui_event_process and duplicate mouse.c in ui/. All editor input is now event-based. 20120317 -------- editor/ehostage.c, editor/med.c: Make do_hostage_window into a proper callback (seems to be unused for now) editor/eswitch.c, editor/med.c: Make do_trigger_window into a proper callback editor/med.c, editor/medrobot.c: Make do_robot_window and do_object_window into proper callbacks, doing both in the same commit because of global recycling editor/med.c, editor/medwall.c: Make do_wall_window into a proper callback. Only one dialog left - the main one. 20120312 -------- editor/centers.c, editor/med.c, ui/dialog.c, ui/file.c, ui/gadget.c, ui/radio.c: Make do_centers_window into a proper callback, iron out some problems that have become apparent 20120305 -------- include/ui.h, ui/file.c, ui/gadget.c, ui/keypress.c, ui/listbox.c, ui/menu.c, ui/message.c, ui/popup.c: Use the gadget-sent events in the dialogs in ui 20120303 -------- d1x-Info.plist, d1xgl-Info.plist, English.lproj/InfoPlist.strings, RELEASE-NOTES.txt: Increment version to 0.57.2 for Mac and RELEASE-NOTES d1x-rebirth.xcodeproj/project.pbxproj, editor/data/, editor/data/curve.pad, editor/data/dummy.pad, editor/data/group.pad, editor/data/lighting.pad, editor/data/med.mnu, editor/data/newobj.pad, editor/data/object.pad, editor/data/objmov.pad, editor/data/pc6x8.fnt, editor/data/pc8x16.fnt, editor/data/segmove.pad, editor/data/segsize.pad, editor/data/test.pad, editor/data/texture.pad, editor/med.c, include/physfsx.h, misc/physfsx.c, ui/ui.c: Actually add editor data files and make sure DXX can find them arch/include/event.h, editor/med.c, include/ui.h, ui/button.c, ui/checkbox.c, ui/dialog.c, ui/gadget.c, ui/icon.c, ui/inputbox.c, ui/listbox.c, ui/radio.c, ui/scroll.c, ui/ui.c, ui/userbox.c: All gadgets now send events 20120109 -------- ui/popup.c: Give the last use of a dialog in ui, in PopupMenu, a callback 20120103 -------- ui/keypress.c: Give the dialog in (presently unused) GetKeyCode a callback ui/menu.c: Give the dialog in (also presently unused) MenuX a callback ui/message.c: Give the dialog in MessageBoxN a callback 20120102 -------- ui/dialog.c, ui/file.c: Give ui_get_filename a callback for its dialog. Happy new year! 20111231 -------- editor/med.c, include/ui.h, ui/menu.c, ui/menubar.c, ui/popup.c: Make editor menubar and associated menus into windows; either remove or make event-based all the B1_* macros 20111218 -------- include/ui.h, ui/dialog.c, ui/gadget.c, ui/keypad.c: Remove redundant canvas, next and prev members in the UI_DIALOG struct 20111127 -------- arch/sdl/event.c: break out of loop in event_send() in case window_send_event() closed the window to prevent invalid read on memory 20111125 -------- 3d/interp.c: Fixed forgotten MALLOC in g3_draw_morphing_model crashing game when rendering morphing robot (created from matcen for example) main/collide.c: Just as in Descent 2, let flares die in lava 20111124 -------- main/collide.c, main/collide.h, main/fireball.c, main/game.c: Smoothed disabling of friendly fire to re-enable splash damage possible when friendly fire is disabled main/physics.c: calling scrape_object_on_wall in each case of HIT_WALL more reliable to properly do hazard surface damage and prevent weapon objects from possibly sliding against walls 20111114 -------- ui/userbox.c: Make ui_userbox_do fully event-responsive main/newmenu.c: Sliders can now be operated with Numpad arrows if numlock if off 20111112 -------- ui/gadget.c, ui/scroll.c: Make ui_scroll_do fully event-responsive, make sure scrolling actually works by calling all controls' ui_*_do functions (like before) 20111106 -------- include/ui.h, ui/dialog.c, ui/listbox.c: Make ui_listbox_do fully event-responsive ui/radio.c: Make ui_radio_do fully event-responsive 20111105 -------- include/ui.h, ui/button.c, ui/dialog.c, ui/gadget.c, ui/scroll.c, ui/userbox.c: Make B1_JUST_PRESSED event-based, leave ui_dialog_do_gadgets early if a key makes another gadget current, make ui_button_do fully event-responsive (but won't *send* events yet) editor/med.c: Fix crash on exit for non-Linux, when it tries to show an editor warning (unfreed blocks) but doesn't have the images to render it ui/checkbox.c: Make ui_checkbox_do fully event-responsive ui/checkbox.c, ui/icon.c: Fix implicit function declaration in last commit, make ui_icon_do fully event-responsive ui/inputbox.c: Say when the event was handled for ui_inputbox_do (was already event-responsive) 20111103 -------- main/net_udp.c, main/net_udp.h: Do not attempt to check for MULTI_PROTO_VERSION when requesting lite_info 20111102 -------- SConstruct, arch/carbon/conf.h, main/inferno.c, main/multi.h, main/net_udp.c, main/net_udp.h, main/vers_id.h: Introduced extra short based on MULTI_PROTO_VERSION for version-independent Multiplayer-compability-check; Changed version to 0.57.2 to make new version checking not cause problems with stable release 0.57.1; Removed old version_major/minor variables from netgame and player structures since DXX handles this independently; Cleaned up old version stuff and copyright messages 20111030 -------- arch/include/mouse.h, arch/sdl/mouse.c, ui/dialog.c: Return 1 (event handled) in ui_dialog_handler for mouse button events if the mouse was in the dialog 20111025 -------- include/ui.h, ui/button.c, ui/checkbox.c, ui/dialog.c, ui/gadget.c, ui/icon.c, ui/inputbox.c, ui/keytrap.c, ui/listbox.c, ui/radio.c, ui/scroll.c, ui/userbox.c: Pass the event to the individual gadgets' 'do' functions, fix compile warnings introduced in last commit 20111023 -------- include/ui.h, ui/dialog.c, ui/gadget.c: Pass the event to ui_dialog_do_gadgets and use it in that immediate function 20111009 -------- main/render.c: Initialise dyn_light using memset, fixing a warning arch/include/event.h, arch/include/window.h, arch/sdl/event.c, arch/sdl/window.c, include/ui.h, ui/dialog.c, ui/file.c, ui/keypress.c, ui/menu.c, ui/message.c, ui/popup.c: Add support for 'modeless' windows - windows that will allow events to be passed on to the underlying window. Intended for the editor main/net_udp.c: Fix comparison is always false warning editor/centers.c, editor/ehostage.c, editor/eswitch.c, editor/info.c, editor/med.c, editor/medrobot.c, editor/medwall.c, ui/dialog.c, ui/file.c, ui/keypress.c, ui/menu.c, ui/message.c, ui/popup.c: Move calls to ui_dialog_do_gadgets to the dialog event handler, making sure ui_event_handler gets called beforehand 20110927 -------- 2d/palette.c, RELEASE-NOTES.txt, editor/eobject.c, editor/group.c, editor/meddraw.c, editor/medrobot.c, editor/mine.c, editor/segment.c, editor/seguvs.c, iff/iff.c, main/aipath.c, main/bmread.c, main/dumpmine.c, main/fvi.c, main/gamemine.c, main/gamesave.c, main/gauges.c, main/newdemo.c, main/newmenu.c, main/piggy.c, main/render.c, main/titles.c, texmap/ntmap.c, texmap/scanline.c, ui/button.c, ui/inputbox.c, ui/keypad.c, ui/keytrap.c, ui/popup.c, ui/scroll.c: Fixed set but unused variables 20110926 -------- main/fireball.c, main/lighting.c: Code consistency checks by _Tyr_; Fixed set but unused variables d1x-rebirth.desktop, SConstruct, misc/physfsx.c: Patches by Hans de Goede: Made the .desktop file follow the official specifications; Added explicit link to libmath for newer versions of binutils; Fixed crash using PhysFS 1.x in PHYSFSX_addArchiveContent() main/kconfig.c, main/menu.c, main/playsave.c, main/playsave.h: Gave throttle it's own sensitivity and deadzone settings; Added patch by Hans de Goede to let Slide-On and Bank-On settings use invert settings from Slide- and Bank-axes 3d/interp.c, arch/ogl/ogl.c, main/bm.c, main/endlevel.c, main/object.c: Avoided variable array initializations which some compilers do not like; Also made sure declarations happen first inside (sub)functions; Fixed set but unused variables 20110925 -------- main/game.c: Fixed misuse of gr_bitblt_find_transparent_area() caused rear view to be shifted on some cockpits 20110924 -------- main/fvi.c, main/gameseg.c, main/object.c: Consistency check for segment number in find_vector_intersection() and obj_create(); Added more debug output for invalid segment numberin get_seg_masks() main/cntrlcen.c, main/newdemo.c, main/switch.c, main/wall.c, main/wall.h: Reworked wall_toggle() to work with index for segnum instead of a pointer, hopefully making the consistency check less error prone 20110923 -------- main/state.c: When restoring Coop players and make turn them into ghosts perform a check if this player is actually a valid player so we do not just blindly use any object number from a possibly uninitialized player structure 20110921 -------- main/net_udp.c: Streamlined joining, rejoining, disconnecting players and timeouts, getting rid of unwanted rejoin messages and let host remove a player for good without rejoining it via pdata packet to really get rid of lossy or unwanted players; Care for rollover of pkt_num of stored mdata packets main/net_udp.c: Added wrapper functions dxx_sendto and dxx_recvfrom to collect simple statistics about amount and size of packets sent/received per second; Actually fixed packet scheduling in main UDP frame - was sending more than intended - stupid me 20110919 -------- main/multi.h, main/net_udp.c: Reworked Packet Loss Prevention: If an important packet could not be recovered until it timed out, dump player who failed sending/receiving it; Noloss queue can proces spackets until a certain traffic has been reached; In main UDP frame schedule different types of packets depending on PPS to decrease traffic produced in one frame, hopefully preventing too much loss in high-traffic situations; Small code cleanups; Added new dump signal for loss of important packet; When dumping player also disconnect that one in case the dumped player does not accept the signal main/playsave.c: Removed saving/restoring the state of Packet Loss Prevention from Netgame profiles 20110915 -------- main/laser.c, main/laser.h, main/multi.c, main/multi.h, main/multibot.c, main/net_udp.c, main/net_udp.h: Added new priority level for MDATA packets to also send them ASAP without the need for an ACK; Streamlined sending multibot and fire packets and on the way artificially and automatically scaling fire rates, energy/ammo usage and damage of weapons in Multiplayer to decrease traffic easy way without changing the Gameplay 20110914 -------- INSTALL.txt, README.txt, SConstruct, arch/carbon/conf.h, d1x.ini, include/args.h, main/inferno.c, main/kmatrix.c, main/kmatrix.h, main/menu.c, main/multi.c, main/multi.h, misc/args.c: Removed support for IPX protocol and MS-DOS-Multiplayer-compability due to age and lack of real need and to really improve on the Multiplayer without adding too much complexity for backwards-compability 20110913 -------- README.txt: Mention Mac command keys arch/carbon/conf.h, d1x-rebirth.xcodeproj/project.pbxproj: Define USE_TRACKER for Mac OS X, remove reference to deleted cfile.h 20110912 -------- arch/sdl/mouse.c, ui/mouse.c: Move EVENT_MOUSE_DOUBLE_CLICKED support from ui/mouse.c to arch/sdl/mouse.c for tidiness and to possibly use it outside the editor INSTALL.txt: Put back the instructions for installing the PC data 20110826 -------- main/ai.c: Due to conversion from fix64 to fix Boss_dying_start_time was not 0 when saving even if boss was not dead - fixed; Fixed warning about set but unused variable 20110720 -------- main/menu: Added Polygon model viewer and GameBitmaps viewer in non-Release build for debugging, messing around, DXX-Redrawn, etc. 20110719 -------- main/net_udp.c: Properly call multi_leave_game() when host leaves multi game to let clients exit smoothly English.lproj/InfoPlist.strings, d1x-Info.plist, d1xgl-Info.plist, main/inferno.c: Keep copyright information up to date README.txt, debian/control, debian/copyright, debian/rules: Changed my eMail address 20110716 -------- main/songs.c: Correctly proceed to new Redbook track if songnum != Song_playing (hopefully - to confirm); Using songs_stop_all() in songs_uninit() to clear redundancy; added some notes to functions to shine a bit light on the mess of some functions; Also if there's no escape song, continue level music arch/sdl/rbaudio.c, main/inferno.c: Fixing Redbook hooks: Initialize last_check_time in RBACheckFinishedHook(); Execute RBACheckFinishedHook() during EVENT_WINDOW_DRAW in standard_handler() as EVENT_IDLE rarely happens if you have a shivering Joystick connected for example arch/carbon/conf.h, SConstruct: Changed version to 0.57.1; Updated release notes 20110715 -------- arch/sdl/digi.c, main/digi.h, main/songs.c, misc/hmp.c: Bail out of hmp_reset() if midiOutOpen fails and return error with -debug set; execute hmp_reset() before first song plays; renamed digi_win32_stop_current_song() to digi_win32_stop_midi_song() to keep naming convention; Fixed some compiler warnings main/net_udp.c, main/net_udp.h: Fixed typo in Packets per sec. in GAME_RULES screen; Reduced max amount of games shown on netlist to 900 to reduce RAM usage... as if we'd ever reach this main/automap.c: properly check and fix viewMatrix in free flight auotmap 20110714 -------- main/collide.c: When colliding with robot not controlled by us in Multi-Robot game do not apply force or damage - wait until the robot is under our control - preventing juggeling robots back and forth between players and creating massive damage 20110713 -------- arch/sdl/event.c, arch/sdl/key.c, main/kconfig.c, main/menu.c: Stability fixes: avoid somfusions with same named variables in one function; Properly sort out players from player list that use too long filenames; Removed call for gr_set_fontcolor in kconfig where no canvas is set, causing crashes when trying to reassign a button, key or axis 20110712 -------- main/wall.c: Add fallback routine from D2 source in wall_frame_process() to automatically set open-flag if wall state is set to opened main/multibot.c: Fixed uninitialized bytes in multi_do_create_robot_powerups() and two set but unused variables 20110710 -------- main/gameseg.c: Added complex error output if illegal segnum passed to get_seg_masks(); Fixed warning about set but unused variables 20110709 -------- main/lighting.c: Added new dynamic light calculation which works with find_connected_distance() preventing vertecies to be lit up without connection to light source but still maintaining illumination. Still deactivated as it needs more optimization - planned for 0.58. Removed old alternative dynamic lighting which was suppoed to work via fvi but way slower than the new one 20110708 -------- main/net_udp.c: Slight improvement for Packet Loss Prevention: Be able to send to 35 packets per call of net_udp_noloss_process_queue() and also let counter only increase if a packet was actually sent, making sure the queue is not stuck on the first 5 packets in the list arch/sdl/digi.c: Make sure hmp_reset() is only executed if a song was playing 20110704 -------- main/game.c, main/gamerend.c: Only call show_netplayerinfo() if GM_MULTI is set and reset netplayerinfo_on in game_setup() 20110702 -------- main/ai.c: When initializing ai object correctly initialize Ai_local_info to prevent glitches like random submodel angles 20110701 -------- d1x.ini, main/inferno.c, main/net_udp.h, misc/args.c: Made formatting for help text more consistent and prettier; Somewhat changed the code for help text so we can use variables in the help text. For example: If we change MAXIMUM_FPS, it will automatically be displayed in the help text without manual editing needed 20110630 -------- editor/group.c, editor/ksegsize.c, editor/meddraw.c, editor/segment.c, editor/seguvs.c, include/editor/editor.h, main/automap.c, main/fireball.c, main/gamecntl.c, main/gameseg.c, main/gameseg.h, main/lighting.c, main/render.c, main/render.h, main/segment.h: changed variables and pointer carrying vertex indexes from short to int to handle levels with over 900 segments properly 20110629 -------- main/newdemo.c: Due to design issue in demo system initial recording of doors could place same texture on front and back sides of doors - fixed as good as possible (wish I could expand the demo format) 20110628 -------- main/state.c: Fixed possible memory corruption when saving Current_mission_filename which is not necessarily a 9 byte long allocated string; Bit safer string handling with snprintf; Fixed set but unused variables like a boss main/net_ipx.c: Correctly disable/initialize Multiplayer features not supported by IPX games for compability; Removed show_games_rules as there isn't much useful to show there; Some more code simplicity 20110627 -------- main/switch.c: when entering secret level reset Control_center_destroyed when we start the level and not in between as it will break sending endlevel packets 20110624 -------- main/net_udp.c: Fixed object sync for latecoming clients which was broken due to a very, very, VERY stupid mistake... 20110623 -------- main/hud.c: PlayerCfg.MultiMessages was supposed to only show messages of class HM_MULTI but turned out to only block HM_REDUNDANT, too. Fixed this copy/paste error of mine main/laser.c: For Hotshot and above made homing missiles turn to player a bit less agressive which is hardly noticable but slightly increases the chance to shake off a projective even if dodged without perfect timing. This makes possible to survive in case a player/bot shoots several homing projectiles in spread fashion 20110620 -------- main/lighting.c: in compute_light_emission() handle RT_NONE for delayed explosion fireballs 20110617 -------- main/physics.c: By using fixed distance bumping for fix_illegal_wall_intersection making the whole process much more reliable on sharp edges 20110613 -------- main/sounds.h: Condition for sound sample number for SOUND_CHEATER was reversed between Shareware and Full Release content 20110609 -------- main/render.c: Saturate colored dynamic light just like normal one - makes the hwole thing a bit less colorful but makes for better balanced color mixing (theoretically) and does not reduce static light 20110607 -------- main/render.c: Definition of dynlight_time should have been static to archive timed light calculations 20110606 -------- main/menu.c, main/playsave.c: For all filename strings use PATH_MAX as size, make sure they are inited correctly and only fill them with snprintf instead of sprintf 20110604 -------- main/lighting.c: Since set_dynamic_light() is not necessarily processed each frame, added own counter for delayed precession of vertex-clight calculation; Added possibility to page in a bitmap in case an object which has never been rendered before is supposed to cast light visible by the player main/sounds.h, main/weapon.c: Fix weapon selection sounds fpr pc shareware and do not allow selecting weapons not available in this content (i.e. if obtained by cheat) main/multi.c: for flexibility in terms of modding, allow player ship textures in Multiplayer be <= N_PLAYER_SHIP_TEXTURES and not hit Assert but pull out Eroor if there are more 20110601 -------- 2d/font.c, 2d/palette.c, 2d/pcx.c, arch/linux/hmiplay.c, arch/ogl/gr.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, editor/group.c, editor/kmine.c, editor/med.c, editor/mine.c, iff/iff.c, include/physfsx.h, main/ai.c, main/bm.c, main/bmread.c, main/cntrlcen.c, main/cntrlcen.h, main/credits.c, main/custom.c, main/digiobj.c, main/dumpmine.c, main/effects.c, main/effects.h, main/endlevel.c, main/fuelcen.c, main/fuelcen.h, main/game.c, main/game.h, main/gamefont.c, main/gamemine.c, main/gamemine.h, main/gamesave.c, main/gameseq.c, main/inferno.c, main/menu.c, main/menu.h, main/mission.c, main/newdemo.c, main/newmenu.c, main/object.c, main/piggy.c, main/piggy.h, main/player.c, main/playsave.c, main/polyobj.c, main/polyobj.h, main/powerup.c, main/powerup.h, main/robot.c, main/robot.h, main/segment.h, main/songs.c, main/state.c, main/switch.c, main/switch.h, main/text.c, main/titles.c, main/vclip.c, main/vclip.h, main/wall.c, main/wall.h, main/weapon.c, main/weapon.h, misc/hmp.c, misc/ignorecase.c, misc/physfsx.c, misc/strio.c, ui/keypad.c, ui/menubar.c: Got rid of cfile code: Renamed cfile-functions to use PHYSFSX-naming convention, Replaced cfile-macros with proper PHYSFS(X) calls; Introduced PHYSFSX_exists() which can check case-sensitive or case-insensitive to give more flexibility with game content main/game.c: Executing timer_update() at the beginning of calc_frame_time in case event_process() taking a significant amount of time to reach the game window and therefor could make FrameTime be inaccurate main/lighting.c: Added proper colored lighting handling for RT_POWERUP which I not noticed was wrong before ... darn dim glowing powerups 20110530 -------- arch/include/digi_audio.h, arch/include/digi_mixer.h, arch/sdl/digi.c, arch/sdl/digi_mixer.c, main/digi.h, main/digiobj.c: Added own channel management to SDL_mixer sound interface since the builtin channel management of this lib cannot handle our needs; Little code cleanup 20110528 -------- main/net_ipx.c, main/net_udp.c: Made netgame setup menu more flexible towards (constant or temporary) changes in available game modes 20110526 -------- arch/sdl/event.c: In event_process() if a window closes while being drawn and there isn't a previous window we can get the next from just finish processing for this frame 20110525 -------- main/game.c, main/multi.c, main/multi.h, main/net_udp.c, main/net_udp.h: Added multi_send_data_direct to send multibuf to a specific player (i.e. Host<->Client, not Client<->Client); Overhauled kill sending/receiving and computation to rely in host information about game_mode-related variables (team_vector, Bounty_target) which are vital for consistent kill computation; Added function to send/update game_mode-related variables and solve /move command with this as well instead of workaround via updating lite_info; Introduced /move commend from Descent2 to move players between teams 20110522 -------- editor/med.c, main/game.c, main/gameseg.c, main/gameseq.c, main/menu.c: Like in BigEndian builds do netmisc_calc_checksum() only with expected items of segment/side struct to prevent different checksums in case these structs change; Fixed several issues when building with editor; Fixed compiler warning regarding set but unused variable main/net_udp.c: When restoring Coop setting from netgame profile don't forget to fix max players variable 20110520 -------- INSTALL.txt, RELEASE-NOTES.txt: Updated docs and fixed some typos main/net_ipx.c, main/net_udp.c: Rearranged code to check for netgame-closed flag and refuse-players flag so they are updated correctly if another part of the code changes the menu item without activating it main/automap.c, main/menu.c, main/playsave.c, main/playsave.h: Made Automap Free Flight controls an optional feature which can be set in MISC OPTIONS; Fixed possible path string issue in plyr_read_stats_v() and fixed compiler warning regarding set but unused variable main/net_udp.c: Making D1X- and D2X-Rebirth more similar in behavior of which player limit is needed to start team-based game in both RELEASE and DEBUG builds 20110519 -------- main/fvi.c, main/fvi.h, main/physics.c: Improvement for fix_illegal_wall_interesection(): Move away from wall in right angle - not towards center. This improves the bumping in many situations and prevents ship getting stuck in small segments. Simplified and optimized code as well and removed check for degenerated Segments as not needed with this approach; Fixed some compiler warnings regarding set but unused variables main/multi.c: Reset new_Bounty_target after using it and let host add a number on how often Bounty is reassigned. Both additions should help keeping target correct no matter how if multiple packets of the same type are disordered, delayed or both main/physics.c: for fix_illegal_wall_intersection() try using the distance we moved to move out from the wall. Just in case it's a sane value, i.e. > 0 and <= obj->size/2 arch/ogl/gr.c, main/game.c: Removed key_flush() call from save_screen_shot() - not needed anymore due to new input reading and only screws up ingame controls 20110516 -------- main/menu.c: for debug build ignore player Highest_level_index when starting a mission, making *Load Level* entry in main menu obsolete; Fixed two compiler warnings regarding set but unused variables 20110515 -------- main/multi.c: Solved possible issue when setting new Bounty_target via host messing up scores or new target itself - only set if player decided why to unset Bounty_target, keeping code flow and game logic in order; Fixed two compiler warnings regarding set but unused variables RELEASE-NOTES.txt: Added more info: M3U-support, GCC 4.6 warnings, more tracker infos 20110513 -------- main/multi.c: Send player position also when multi_send_player_explode() is called so powerups drop at the right spot in case the respawn packet arrives first 20110507 -------- arch/carbon/conf.h: Enabled Tracker support for Mac OS RELEASE-NOTES.txt, README.txt, SConstruct, arch/carbon/conf.h: Changed version from 0.56 to 0.57; Added first draft for RELEASE-NOTES.txt; updated docs main/endlevel.c: Taken out Render_depth reduction of Endlevel sequence in Software rendering build; Fixed two compiler warnings regarding set but unused variables main/automap.c: Don't call automap_process_input() if autmap_key_command() returns 1 preventing input mess; Fixed two compiler warnings regarding set but unused variables 20110505 -------- main/gauges.c, main/multi.h, main/net_udp.c, main/net_udp.h, main/playsave.c: Host can now decide (again) if players are allowed to display enemy names on HUD main/gauges.c, main/piggy.c, main/piggy.h: When using PC Shareware pigfile do not show key icons in CM_FULL_SCREEN since pigfile does not have these icons d1x-rebirth.desktop, debian/changelog, debian/control, debian/copyright, debian/rules: Update for Debian packaging stuff main/lighting.c: Correctly handle light computation of objects with render_type RT_LASER 20110504 -------- editor/segment.c, main/fvi.c, main/gameseg.c, main/physics.c, main/segment.h: Since current approach to improve wall collisions prevented the player to enter segments which basically are too small for the player ship, added simple bumping function via object_intersects_wall(); Also when validating segments check for segment degeneration outside the editor build, too and set flag in segment structure for all different purposes but right now helps us to disable bumping when encountering degenerated segments and not break such levels main/endlevel.c: Make sure the big explosion at the end of the escape sequence also uses blending if transparency effects are activated main/multi.c: Fix crash in multi_maybe_disable_friendly_fire() when killer == NULL 2d/font.c: mipmapping was always on for fonts due to changed filtering code in ogl.c main/physics.c: To compensate fewer FVI runs in lower FPS and wall penetration caused by strong forces allowed fix_illegal_wall_intersection() to move an object out of the wall half it's size improving the collisions once more main/segment.h, main/state.c: Due to increased size of MAX_SEGMENTS old savegames became incompatible. To compensate added MAX_SEGMENTS_ORIGINAL with the original segment amount and read certain savegame info with this info when dealing with standard-sized levels and use Highest_segment_index when dealing with larger levels which are incompatible with older versions of the game anyways. Makes savegame site more efficient and still maintain backwards compability 20110424 -------- d1x-rebirth.xcodeproj/project.pbxproj, main/newmenu.c: Check if a menu closed in a subfunction before setting it's return value, fixing crash when levels are mismatched in multiplayer; Small tidy up for Xcode project 20110422 -------- 2d/rle.c, SConstruct, main/segment.h, main/texmerge.c: Expanded possibilities for level authors: RLE- and Texture-cache accepts textures bigger than 64x64, only limit being Texture width must be equal height; Increased maximum amount of Segments from 900 to 9000 - not dynamically allocating them, yet arch/sdl/mouse.c, main/kconfig.c, main/menu.c, main/playsave.c, main/playsave.h: When reading ingame controls only flush mouse delta timer-based since reading is event-based already, allowing high precision no matter the game speed; Removed Mouse smoothing/filtering as it's now unnecessary due to event-based motion handling 2d/rle.c, main/texmerge.c: Fixes for RLE- and Texture-cache modifcations: Before freeing now must check if bitmap is already allocated main/menu.c, main/net_udp.c, main/playsave.c, main/playsave.h: Remember previously set up netgame variables in pilot-related file with extension ngp - due to feature consistency for UDP only 20110421 -------- main/net_udp.c: When leaving game and still sending extras, don't forget to update the timer so we won't get stuck in an infinite loop arch/sdl/key.c: Added SDLK_WORLD_** symbols to keyboard array to enable layout specific keys and make the game more flexible 20110420 -------- main/multi.c, main/state.c: Resolved termination issue when reading and comparing callsigns fro Coop savestates; Added scores sending after Coop savestate loading as unrestored players will send them when loading new level 20110418 -------- arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, main/config.c, main/menu.c, main/songs.c, main/songs.h: Fix broken m3u playlist support (in jukebox_play() path resolving); point to default descent.m3u playlist for Mac OS X (will be included in bundle); better error reporting in mix_play_file(); only make relative Jukebox path in the menu absolute after browsing it - relative paths are more flexible; allow select_file_recursive() to figure out PhysicsFS relative paths passed to it; stop the music if Jukebox is chosen and unavailable (used to just keep playing the last song) 20110416 -------- main/gamecntl.c, main/gauges.c: Due to controls rewrite was not possible anymore to send multiplayer messages while being dead - added specific exception to allow this; Rewrote show_HUD_names to only show names, indicators or typing string for enemy players when they are not cloaked misc/hmp.c: Check for hmp before pausing/resuming it 20110414 -------- main/kmatrix.c: Fixing km struct being used after it's being freed by closing the window in EVENT_WINDOW_DRAW 20110413 -------- main/net_udp.c, main/net_udp.h: Improved security for UDP protocol: Add checks for correct packet size and - if possible - valid sender address (valid player) and making sure Clients only accept packets meant for Clients and Hosts only accept packets meant for Hosts main/fvi.c, main/physics.c: Bit more safeguarding in find_plane_line_intersection() and as a result less agressive but more beautiful back-bumping on illegal wall interesections; Scaling of movement from PhysTime to FrameTime now done with vector math functions main/credits.c: Fixing unfreed buffer when credits_show() was called but there was nothing to show me main/lighting.c: Reset obj_color for colored object lights when object does not return any usable color so the object will cast white light at least 20110412 -------- main/gauges.c, main/multi.h, main/net_udp.c, main/net_udp.h: Little fix for typing-indicator in multiplayer - was showing comma even if no player name was displayed; Removed team_vector from UDP lite_info structure - it's not needed; Increased UDP_NETGAMES_PAGES to actually show 3000 possible games include/gr.h, main/bm.c, main/bm.h, main/gamesave.c, main/lighting.c, main/multi.c, main/object.c, main/object.h, main/piggy.c, main/render.c, main/state.c: Execute set_dynamic_light 60 times per second max since more would just be a waste of CPU time; When executing set_dynamic_light, process ALL lights; Instead of storing light color in objects, do it on-thy-fly but store bitmap-based color in grs_bitmap - vastly speeds up colored dynamic lights; Improved saturation for vertex lighting to make light color a bit more subtile main/playsave.c: kconfig weapon cycling fields changed after 0.56 release will automatically fix if version number changes on next release 20110411 -------- main/game.c, main/gamecntl.c, main/gamerend.c, main/gauges.c, main/multi.c, main/multi.h: Improved syntax for Multi messages/commands: Commands starting with '/' and those accepting arguments as well as Player/Team messages require space after ':' ; Added indicator on HUD to show if a player is typing a message to prevent accidential kills main/hud.c, main/hudmsg.h, main/powerup.c, main/weapon.c: Introduced HUD message class HM_MAYDUPL for messages that may appear once per frame but the player might not able to supress via option 20110410 -------- main/net_udp.c: Allow multi_send_fire when necessary and not crop to PPS so fix weapons with high firing rate main/game.c, main/gamerend.c, main/gauges.c, main/net_udp.c, main/titles.c: Fixed text-related annoyances: "Show reticle names" now named "Show player names on HUD"; Fixed positions of strings TXT_CLOAKED and TXT_CRUISE in CM_FULL_SCREEN; Fixed typo in tracker timeout screen; Fixed scaling of tab_stop in briefings (again); Removed some little D2 code for briefings as it broke some briefing screens INSTALL.txt: Tell people about The Unarchiver for installing from the Mac game CD (thanks, Jonathan!) arch/ogl/gr.c: Smash texture list when switching between window mode and fullscreen prevent invalid textures; Made code to capture Screenshots more similar between OpenGL and OpenGL ES main/automap.c: Allow completely free movement in the automap. It will rotate relative to the viewer. 20110408 -------- main/net_udp.c: Allow multi_send_fire when necessary and not crop to PPS so fix weapons with high firing rate 20110407 -------- 3d/draw.c, 3d/interp.c, 3d/rod.c, arch/ogl/ogl.c, include/3d.h, include/ogl_init.h, main/endlevel.c, main/gamesave.c, main/lighting.c, main/lighting.h, main/menu.c, main/morph.c, main/multi.c, main/object.c, main/object.h, main/playsave.c, main/playsave.h, main/polyobj.c, main/polyobj.h, main/render.c, main/state.c, main/terrain.c: Made lighting code work with actual RGB values and added feature to let certain objects emit colored dynamic light as well as let mine flash red when control center destroyed (OpenGL-only at the moment) main/physics.c: When sliding along a wall keep wall_part sane to ensure good velocity for slide 20110405 -------- SConstruct, arch/win32/ipx.c, d1x.ini, include/args.h, main/inferno.c, main/menu.c, main/multi.h, main/net_ipx.h, main/net_udp.c, main/net_udp.h, misc/args.c: Client-side implementation for Tracker support by Matt "1360" Vandermeulen including improvements in udp_dns_filladdr and IPv4/IPv6 compability; Very little adjustments by me, too including IPv6 support for Windows (untested); Actual tracker code will follow later as seperate branch when it's done 20110329 -------- main/cntrlcen.c, main/cntrlcen.h, main/state.c: Dead_controlcen_object_num should be set when a new level starts in debug build, too; Setting Total_countdown_time when loading a savestate so SEF-DESTRUCT SEQUENCE ACTIVATED sample will not play soon as timer reaches 0 20110328 -------- main/endlevel.c, main/newdemo.c: Properly record the event of reset_rear_view() while switching levels to make it work right when rewinding as well; Properly record Countdown seconds for each newdemo frame instead of second change to get display showing up right while playback and still preserving backwards compability arch/ogl/gr.c: Fixes for OpenGL ES implementation 20110327 -------- main/physics.c: Another rework for anti-stuck-bumping: Execute after calculation of velocity and add fvi check to make sure we deal with an actual wall collision 20110314 -------- main/fvi.c, main/physics.c: Again reworked new bump hack to only apply when fate == HIT_WALL (to not break level SKYBOX) and made bumping by distance between object position and wall hit point; Removed/handled some safety checks in find_plane_line_intersection() to make sliding along joining edges smoother again while bad values *should* be handled in pyhsics.c and not make object warp-crashing tru the whole level or stuck in walls (fvi code should still be rewritten tho) 20110310 -------- main/kconfig.c: Due to lazy copy&paste sliding up/down speed was divided by 2 - fixed 20110306 -------- main/songs.c: Be safer not interrupting other ports of descent or the original MS-DOS game when it comes to reading song files: Try reading from MISSION_NAME.sngdxx to have a way reading a song file for a specific mission outside the mission's HOG, next try reading from descent.sngdxx which shall serve as an alternative song file specifically for DXX and then try descent.sng. This should give authors enough possibilities to add OSTs for all different versions of the game without the need to publish different versions of their missions 20110224 -------- 2d/canvas.c: Fix for last revision: Correctly initialize cv_fade_level and cv_blend_func when creating initializing a canvas 20110223 -------- 2d/2dsline.c, 2d/canvas.c, arch/ogl/gr.c, arch/ogl/ogl.c, arch/sdl/gr.c, include/3d.h, include/gr.h, include/ogl_init.h, main/ai.h, main/console.c, main/effects.h, main/gamerend.c, main/gauges.c, main/hud.c, main/menu.c, main/multibot.c, main/newmenu.c, main/object.c, main/playsave.c, main/playsave.h, main/render.c, texmap/tmapflat.c: Added cv_fade_level to canvas structure to replace Gr_scanline_darkening_level; Added cv_blend_func to canvas structure to set blending; Introduced gr_settransblend to set cv_fade_level and cv_blend_func; Added function to set normal blending, additive alpha blending and additive color blending; Moved Special transparency effects from g3_draw_bitmap to render_object to set individual transparency and/or blending for each object outside of OpenGL-specific code; Added special blending for fuelcenter and force field effects as well; Removed unused LASER_HACK code; Renamed OglAlphaEffects variable of PalyerCfg to AlphaEffects as I plan to implement this kind of effects for Software renderer, too 20110221 -------- misc/strutil.c: Fix a critical bug in string_array_add - when d_reallocing the buffer containing the string data, update all the pointers in '*list' as well as next_str, preventing ugly crashes 20110218 -------- arch/ogl/ogl.c, include/ogl_init.h, main/endlevel.c, main/object.c: Draw laser effects with special blending instead of disabled DepthMask; Added special blending for transparency effects as well to let them kick more ass; Corrections while rendering outside part of endlevel sequence with disabled depth testing and dynamically changing Render_depth to make the mine exit visible again while not rendering the exit tunnel tru the planet terrain arch/ogl/ogl.c: Set zNear for gluPerspective to 0.1 to prevent ugly clipping while passing illusory walls; Set zFar to 5000.0 to prevent disappearing automap in large distance - all still sane enough for Intel chips so my eeePC is safe nyahahaha 20110215 -------- main/gamecntl.c: Fixed PRShot feature which was accidentially broken while implementation of OpenGL ES support 20110214 -------- d1x.ini, include/args.h, main/ai.c, main/ai.h, main/automap.c, main/cntrlcen.c, main/collide.c, main/config.c, main/config.h, main/fvi.c, main/game.c, main/game.h, main/gamecntl.c, main/gamerend.c, main/gameseq.c, main/gameseq.h, main/gauges.c, main/inferno.c, main/kconfig.c, main/laser.c, main/menu.c, main/multi.c, main/net_ipx.c, main/net_udp.c, main/physics.c, main/player.h, main/render.c, main/state.c, main/titles.c, main/titles.h, misc/args.c: Moved all these unsorted global cheat variables to a handy structure; Simplified reading of the cheats without trying to make it complicated so no one finds them (everyone can get the source); Removed one or two cheats which carry more garbage than they are worth; Added replacement for the bittersweet cheat; Made FPS Counter an option of Graphics menu main/credits.c, main/titles.c: For credits and briefings moved all code happened in EVENT_IDLE to EVENT_WINDOW_DRAW since a jitterish Joystick could slow down text rendering 20110212 -------- arch/inlcude/window.h, arch/sdl/event.c, arch/sdl/window.c, main/game.c: New approach to handle a bunch of closing windows - removed window_do_close() again, reworked game_leave_menus by checking window_get_front() and closing this window until it's Game_wind, while event_process checking if window still exists after drawing and if not, take next window from previous which should be updated by then 20110211 -------- main/gamecntl.c, main/kconfig.c, main/newmenu.c: Controls.select_weapon_count needs to be incremented differently to get non-0 when we want to select the laser type weapon; Readded jumping from first to last item in newmenu and vice versa 20110210 -------- main/automap.c, main/gauges.c, main/gauges.h, main/kconfig.c, main/newmenu.c, main/newmenu.h: Fixed broken FlightSim indicator on Automap; Fixed Assert for using mouse buttons in kconfig (which can react to UP and DOWN states); Added scrolling support for menus flagged tiny_mode and all_text arch/ogl/gr.c, arch/sdl/gr.c, d1x.ini, include/args.h, main/inferno.c, misc/args.c: Simplified ogl version of gr.c in terms of SDL video flags and fullscreen toggle; Added command-line/INI option to remove borders from windowed program main/multi.c: Fixed compiler warning related to generation of game_id for Coop Savegames arch/ogl/ogl.c, main/gauges.c: Added secondary weapon indicators to new reticle types; Fixed disks being drawn as circles - whoops 20110209 -------- main/ai.c, main/game.c, main/gamecntl.c, main/menu.c, main/multi.c, main/multi.h, main/state.c, main/state.h, main/titles.c: Reintroduced Savegames for Coop games using the original Descent2 implementation but correctly handling player slots in their pre-loading state preventing accidential player shifting which never really worked in the original game and we do not want with UDP anyways - was all tested but still might need a fix or two; Added some missing initializations for saving players and AI stuff; Completely ripped out remnants of saving between levels code arch/ogl/ogl.c: Fixed memory leak produced by drawing circles and disks 20110206 -------- arch/include/key.h, main/automap.c: Increased key repeat values to react a little more like the MS-DOS version of the game but a little slower so I can still stop at the correct item; In automap reorganized control_info swapping as well as wiggle state handling to properly work in connection with the new input handling and Multiplayer where game is not paused 20110203 -------- main/automap.c, main/gamecntl.c: Little fixes for recent kconfig/event overhaul: Automap inputs read by kconfig should be processed by input rather than idle and automap frame calculations should be done while drawing; Fixed drop_bomb_count which could roll over to 255 dropping bombs without end arch/include/window.h, arch/sdl/event.c, arch/sdl/window.c: Included new window structure flag w_closing_state and let window_close() set this flag - after drawing all windows, check them again and call window_do_close() which then actually closes the window(s) marked to. Solving all sorts of problems when windows close while being drawn (network error messageboxes, game_leave_menus(), etc.) 20110202 -------- arch/include/event.h, arch/include/joy.h, arch/include/key.h, arch/include/mouse.h, arch/sdl/event.c, arch/sdl/joy.c, arch/sdl/key.c, arch/sdl/mouse.c, main/automap.c, main/endlevel.c, main/game.c, main/gamecntl.c, main/inferno.c, main/kconfig.c, main/kconfig.h, main/multi.c, main/newmenu.c, main/slew.c: Added event types for all input actions; Rewrote kconfig code to work with events; static defined inputs will not trigger kconfig-mapped inputs anymore; Simplified keyboard, mouse and joystick code a lot due to event-based handling; Added function to toggle SDL key repeats on and off; Put timer_update() to event_process; Removed return when event_poll() is idle to get cursor hiding to work again; Added a small delay between cursoe hiding and re-enabling to cursor will not accidentially enable by SDL event centering cursor while hiding arch/ogl/ogl.c: After rendering Reboot reticle, reset glLineWidth to default value again main/fireball.c, main/gameseq.c, main/net_ipx.c, main/net_udp.c: Little more smoothness for Multiplayer: Before dropping Powerups in random segment, make sure it's accessible by the player who drops it; Got rid of goto in InitPlayerPositions() and made code more D2-ish; Allow host to send 50 object/extra packets per second which does not overload network stack, yet but speeds up joining 20110126 -------- arc/sdl/event.c: In event_process() check for wind->next before sending EVENT_WINDOW_DRAW in case drawing will free wind 20110124 -------- main/physics.c: Revamped what previously was the BUMP_HACK by checking if an object is actually intersecting a segment and move it out towards segment center just after the initial object movement composed by fvi and before velocity is made - should make inaccurate wall collisions a bit smoother and prevent objects from goind inside or through walls, too main/physics.c: Added some new conditions to the bumping code: Only bump objects which can slide (alive robots and players) and added a count making sure this function can never get stuck in an infinite loop main/collide.c, main/fireball.c: Some improvements and cleanups for Persistent Debris: Let them bounce, added drag and let them explode on hazardous walls 20110123 -------- main/ai.c: Taking out one Assert in init_boss_segments() stopping the program if there is more than one boss in level - taking out because it's not fatal or unsafe to do that main/physics.c: Increasing the collision count for objects so there can be 8 for all objects; also do not increase count when colliding with a powerup as it should not change our movement main/playsave.c: For new player, set ReticleSize to 0 which is the smallest size 20110122 -------- main/console.c, main/game.c, main/gamerend.c, main/gauges.c: Added timer_update() to stop/start/reset_time() functions so resumed last_timer_value will be precise; Added new FPS counter which actually does count the frames rendered per second and is less irritating; Added timer_dleay2 call to console to not stress CPU too much; Imporoved placement for show_time(), multi messages main/cntrlcen.c, main/cntrlcen.h, main/fuelcen.c, main/multi.c, main/state.c: Handling Controlcen countdown Descent2-way to make code more similar but more importantly to avoid issues in Multiplayer levels which do not even have a Controlcen type Station causing the game get stuck in an infinite loop; Fixed small issue parsing killreactor command in Multiplayer main/polyobj.h: _POLYOBJ_H definition was not terminated at end of file causing compiling to fail with WORDS_NEED_ALIGNMENT define include/byteswap.h: Added swapping for 64Bit sized integers in case we want to store/read them some day (i.e. new Savegame version storing object instead of object_rw) main/gamerend.c: in show_framerate do not use gr_get_string_size at all but rather use hardcoded coordinates - less CPU-intense main/fvi.c: Removed fvi_a.h and added the asm code from it as comment to fvi.c in case we need it again some day 20110121 -------- main/render.c: Protection for negative array index in find_seg_side was accidentially checking for vv1 != -1 - fixed that 20110120 -------- arch/sdl/jukebox.c, main/digi.h, main/menu.c, main/songs.c: Added a simple random function for the Jukebox; Removed one small printf I once added for debugging 20110119 -------- include/3d.h, main/game.h, main/gamerend.c, main/gauges.c, main/multi.c, main/multi.h, main/net_udp.c: Introducing new BOUNTY Multiplayer game mode by Matt "1360" Vandermeulen ; Fit show_HUD_names code to be more similar to D2X - names display still client-decided tho main/gauges.c, main/multi.c: Fix for showing bounty target in kill list - was not actually checking if player_num == Bounty_target; When Bounty_target player leaves game host must select a new target so the game can proceed; Made Bounty sound play a bit louder main/gamerend.c, main/multi.c, main/multi.h, main/net_ipx.c, main/net_udp.c, main/text.h: On NETGAMES list Bounty mode was not shown since MODE_NAMES define was not adjusted - so in the end introduced GMNames and GMNamesShrt Arrays in multi.c for globally displaying full or short Multiplayer game mode names 2d/bitmap.c, 2d/bitmap.h, 2d/canvas.c, 2d/font.c, 2d/rect.c, 2d/scale.c, 2d/scalec.c, 2d/tmerge.c, 3d/draw.c, 3d/instance.c, 3d/matrix.c, 3d/points.c, 3d/rod.c, 3d/setup.c, SConstruct, arch/linux/alsadigi.c, arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, include/3d.h, include/error.h, include/gr.h, include/maths.h, include/texmap.h, main/fvi_a.h, main/inferno.c, main/piggy.c, main/state.c, maths/fixc.c, maths/vecmat.c, texmap/scanline.c: Retired most of the Assembler code except the generic i386 scanline renderer; Removed all leftovers of Direct3D implementation; On the way make a some code more similar between D1X-Rebirth and D2X-Rebirth 20110118 -------- main/gamecntl.c, main/gameseq.c: Allowing loading a savestate while being in death sequence and resetting Dead_player_camera correctly in init_player_stats_level() so forther death sequences won't screw up main/net_udp.c: In net_udp_send_objects() player_num byte was not considered for mode 1 resulting on incorrect object count for this mode main/net_ipx.c, main/net_udp.c: Instead of calling object/extras sending every frame, use a delay of 100ms between packet send to not overload the network stack 20110117 -------- arch/sdl/event.c: Still send idle events when receiving SDL joystick events, fixing possible joystick issues main/menu.c: No referring to non-existent ogl_maxanisotropy for non-OGL build main/kconfig.c, main/newmenu.c, ui/mouse.c: Fix cursor recentering issues - comment out redundant event_toggle_focus(1) calls in kconfig.c and newmenu.c and use event_toggle_focus(0) in ui_mouse_show() arch/ogl/ogl.c: Before duplicating last pixel column or row in ogl_filltexbuf, make sure we are still in actual bitmap boundaries SConstruct, d1x-rebirth.xcodeproj/project.pbxproj, editor/centers.c, editor/ehostage.c, editor/eswitch.c, editor/med.c, editor/medrobot.c, editor/medwall.c, editor/mine.c, editor/objpage.c, editor/texpage.c, include/editor/editor.h, include/editor/objpage.h, include/editor/texpage.h, include/ui.h, ui/button.c, ui/checkbox.c, ui/dialog.c, ui/file.c, ui/gadget.c, ui/icon.c, ui/inputbox.c, ui/keypad.c, ui/keypress.c, ui/keytrap.c, ui/listbox.c, ui/menu.c, ui/message.c, ui/popup.c, ui/radio.c, ui/scroll.c, ui/userbox.c: Rename ui/window.c to ui/dialog.c to avoid confusion with arch/sdl/window.c, also rename UI_WINDOW to UI_DIALOG, rename all associated functions, constants, parameters, local variables etc too; make a window when making a UI_DIALOG (does nothing yet) SConstruct: opengles variable in SConstruct could be activated by command-line argument opengl main/terrain.c texmap/ntmap.c, texmap/scanline.c: Fixing memory corruptions produced by the scanline renderer; Dynamically allocate y_pointers to free scanline renderer from resolution limits 20110116 -------- 2d/bitblt.c, arch/ogl/gr.c, arch/ogl/ogl.c, include/ogl_init.h, main/menu.c: Added feature to enable Anisotropic filtering is supported by hardware or driver; Reworked way of handling texture filtering information so ingame switching is possible again; Little fix for ogl_get_verinfo which was taken out for ordinary OGL code but should for OGLES main/menu.c: When changing resolutions and Game_wind is present, send EVENT_WINDOW_ACTIVATE shortly so it's canvase will align to the new resolution seamlessly main/titles.c: Generally use PATH_MAX for filename arrays in titles code main/console.c, main/inferno.c: Toggle console by KEY_SHIFTED+KEY_ESC again - as it should be arch/ogl/ogl.c, main/menu.c: in ogl_filltexbuf add pixel row matching color of bitmap edge to get a clean border when filtering cockpit overlay bitmaps; Small text correction for sound menu to fit better on screen 20110115 -------- arch/linux/ipx.c, main/net_ipx.c: Fixed some compiler warnings main/game.c: Due to recent changes in event_poll() game_handler() must call ReadControls() for EVENT_MOUSE_MOVED, too; Little fix for FixedStepCalc() arch/ogl/gr.c, arch/ogl/ogl.c: Fixed alpha limit for ogl_ulinec(), gr_uricle(), gr_disk() 20110114 -------- main/credits.c, main/menu.c, main/net_udp.c, main/scores.c: Fix compile errors introduced when merging main/collide.c, main/fireball.c, main/gamesave.c, main/gameseq.c, main/gameseq.h, main/laser.c, main/multi.c, main/multi.h, main/multibot.c, main/net_ipx.c, main/net_udp.c, main/object.c, main/powerup.c, main/powerup.h, main/weapon.c, main/weapon.h: Removed D1X implementation of multiplayer powerup capping and added D2X code to replace this (UDP-only); Added a bunch of D2X code for general and multiplayer powerup dropping to make codes more consistent to each other; Removed MULTI_PROTO_D1X_VER and MULTI_PROTO_D1X_MINOR defines since they are not needed anymore main/gamesave.c, main/multi.c, main/object.h: In multi_leave_game check for Player_eggs_Dropped before actually dropping to prevent multiple drops in case player quits game after being killed; put console output level of multiplayer powerup cap messagers to CON_VERBOSE; Fixed small compiler warning in gamesave.c due to last commit main/gameseq.c: Using timer_query() instead of clock() in InitPlayerPositions(); Also check up distance up to 10 segments main/game.c, main/gamerend.c, main/gameseq.c, main/gauges.c, main/multi.c, main/multi.h, main/net_udp.c, main/object.c, main/player.h: Added Descent2 Multiplayer features: Kill goals, Allowed play time; Bright players, Invulnerable when reappearing main/collide.c, main/multi.c, main/multi.h, main/net_udp.c: Added feature to optionally disable friendly fire in Team and Coop games main/newmenu.c: Moved scroll arrow one unit to the left to be not pixel-aligned to possible checkbox; Made newmenu sliders only react to spacebar, backspace, left and right since pageup/down is already taken for menu scrolling and all other previous key assignments will not work on most spread keyboard layouts include/console.h, main/console.c, main/gamecntl.c, main/gamerend.c, main/inferno.c, main/kmatrix.c, main/net_ipx.c, main/net_udp.c: Converted console into a window and allow it to show in every part of the game; Fit several poll functions and kmatrix so they won't get interrupted by the console 20110113 -------- arch/include/event.h, arch/include/key.h, arch/include/mouse.h, arch/sdl/event.c, arch/sdl/key.c, arch/sdl/mouse.c, editor/med.c, include/ui.h, main/automap.c, main/gamecntl.c, main/inferno.c, main/inferno.h, main/kconfig.c, main/kmatrix.c, main/menu.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/scores.c, main/titles.c, ui/file.c, ui/keypress.c, ui/menu.c, ui/menubar.c, ui/message.c, ui/mouse.c, ui/popup.c, ui/window.c: For editor, replace use of ui_mega_process() with event_process(), with the editor's own default event handler; add EVENT_MOUSE_MOVED event with event_mouse_get_delta() accessor; add event_key_get() to replace ugly casting; rename mouse_get_button() with event_mouse_get_button() to keep with name convention; only send idle events when there are no input events so editor still works properly (or the same anyway); add and use event_send() function for input events (including idle) 20110111 -------- main/net_udp.c: Fixed Menu setting for AllowedItems which was broken due to changed return value of newmenu_do1 20110110 -------- 2d/disc.c, arch/ogl/gr.c, arch/ogl/ogl.c, include/gr.h, include/ogl_init.h, main/automap.c, main/gauges.c, main/gauges.h, main/menu.c, main/playsave.c, main/playsave.h: Added different reticle types with RGBA and size settings; Apply RGBA and size to FlightSim Indicator; Added Brightness Slider to Graphics options menu; Added OpenGL usage for gr_disk main/credits.c, main/songs.c, misc/hmp.c: Let credits track fade out at the end of text sequence; Fixed usage for RBAPlayTracks - when playing only one track last must be equal first, not 0; In hmp_open changed data from long to int, preventing memory explosion depending on optimisation of the code arch/sdl/timer.c: In timer_update() convert cur_tv to fix scale before substracting from last_tv to get a little more accurate values to F64_RunTime (insignificant tho); Added rollover check for SDL_GetTicks() to timer_delay2() 20110109 -------- main/net_udp.h: Set max UDP packet size to 1024 again (seems some configuration DO have problems with larger packets after all) main/net_udp.c: Fix for rev959: my_pnum must be defined static arch/sdl/digi.c, inlcude/hmp.h, misc/hmp.c: Improvement on the HMP track loop feature by TURRICAN; Added small template fix for descent.hmp which is supposed to be activated soon as we have some kind or Checksum function main/kconfig.c: Mousebutton assigned to CYCLE SECONADARY was actually calling CYCLE PRIMARY 20110106 -------- SConstruct, arch/ogl/gr.c, arch/ogl/ogl.c, include/loadgl.h, include/ogl_init.h, main/gamecntl.c, main/state.c, misc/args.c: Added OpenGL ES support - contributed by Florian Feucht and Oliver Haag main/automap.c, main/gauges.c, main/gauges.h: Draw FlightSim Reticle on Automap display, too arch/ogl/ogl.c: Fix small bug in vertex_array for ogl_ubitblt_i 20110104 -------- d1x.ini, include/args.h, main/gauges.c, main/inferno.c, main/kconfig.c, main/kconfig.h, main/menu.c, main/playsave.c, main/playsave.h, misc/args.c: Introduced FlightSim control scheme for mouse which adds delta values to absolute position to behave like a Joystick; Added Deadzone slider for FlightSim as well as an optional Reticle display to show the positional data on screen; Removed old Mouselook hack in favor of this new feature 20110103 -------- arch/sdl/joy.c, arch/sdl/key.c, arch/sdl/mouse.c, include/args.h, main/kconfig.c, main/kconfig.h, main/playsave.c, misc/args.c: Added Cycle Primary/Secondary to the config panels for keyboard and joystick like in D2X-Rebirth and store them in the designated key/button arrays; Added Cycle Primary/Secondary for Mouse which makes wheel axis cycling unnecessary and also let Weapon Keys be assigned to a Mouse button; If GameArg.NoStickyKeys do flush these keys so they can be used as normal game keys - otherwise ban them; Fixed crash when reassigning mouse button greater than 3; Joystick/Mouse function taking button as argument now check for sanity of this value so they can safely be used in kconfig code and deal with unassigned key values d1x.ini, include/args.h, main/gauges.c, main/hud.c, main/inferno.c, main/menu.c, main/playsave.c, main/playsave.h, misc/args.c: Added feature to disable D2-style Prox. Bomb Gauge; Moved NoRedundancy and MultiMessages toggles from GameArg to PlayerCfg to be set via Misc Options SConstruct, INSTALL.txt: More consistency in SConstruct command-line variables; Added automatic Endianess-checker; Set target to 'd1x-rebirth' no matter if OpenGL or not 20110102 -------- main/credits.c, main/kconfig.c, main/menu.c, main/net_udp.c, main/newmenu.c, main/scores.c: Increasing general mouse functionality all over the game: Mouse wheel now can scroll through menu/listbox items; Right mouse button closes a menu (without the need of these ugly close boxes); Also added mouse-closing capabilities to credits, scores and kconfig menus; While being in UDP Netgames list, override keycode at PAGEUP/DOWN keypress to only flip pages without modifying citem also added messagebox showing TXT_INVALID_CHOICE when invalid netgame was chosen arch/include/key.h, arch/sdl/key.c, main/newmenu.c: Introduced function key_ismodlck to get the status of modifier keys or sticky keys; Let sticky keys survive flush so we can accurately use their real states; Added key repeating via SDL; Depending on status of KEY_NUMLOCK keypad will either be used as numerical or arrow input in menus 20101230 -------- main/newmenu.c, main/menu.c: Fixed glitch in scroll arrow position; Added newmenu_scroll which can scroll through all kind is menu structures including automatically handling NM_TYPE_TEXT items as well as automatically updating scroll_offset; PageUp/Down now scrolls by 10 items, Home/end will select first/last/items of menu creating consistency to listbox behaviour; Fit text for GrabInput to be more understandable 20101228 -------- editor/info.c, editor/med.c, include/editor/editor.h, include/editor/info.h: Make the keypad info display into a window arch/include/event.h, arch/include/joy.h, arch/include/mouse.h, arch/sdl/event.c, arch/sdl/joy.c, arch/sdl/mouse.c, d1x.ini, include/args.h, main/automap.c, main/config.c, main/config.h, main/game.c, main/gamecntl.c, main/inferno.c, main/kconfig.c, main/menu.c, main/newmenu.c, main/playsave.c, main/playsave.h, misc/args.c: Added Sensitivity/Deadzone menu with sliders for each movement based action seperated for joystick and mouse to support all kinds of configuration - regardless the amount of joystick axes and whatnot; SDL_WM_GrabInput does not only capture mouse but also focus keyboard input - changed code to respect this fact and made grabbing a menu option which is enabled by default 20101224 -------- CHANGELOG.txt, SConstruct, d1x-rebirth.xcodeproj/project.pbxproj, editor/autosave.c, editor/centers.c, editor/curves.c, editor/eglobal.c, editor/ehostage.c, editor/elight.c, editor/eobject.c, editor/eswitch.c, editor/fixseg.c, editor/func.c, editor/group.c, editor/info.c, editor/kbuild.c, editor/kcurve.c, editor/kfuncs.c, editor/kgame.c, editor/kgroup.c, editor/khelp.c, editor/kmine.c, editor/ksegmove.c, editor/ksegsel.c, editor/ksegsize.c, editor/ktmap.c, editor/kview.c, editor/macro.c, editor/med.c, editor/meddraw.c, editor/medmisc.c, editor/medrobot.c, editor/medsel.c, editor/medwall.c, editor/mine.c, editor/objpage.c, editor/segment.c, editor/seguvs.c, editor/texpage.c, editor/texture.c, include/editor/centers.h, include/editor/editor.h, include/editor/ehostage.h, include/editor/eobject.h, include/editor/eswitch.h, include/editor/info.h, include/editor/kdefs.h, include/editor/kfuncs.h, include/editor/macro.h, include/editor/meddraw.h, include/editor/medlisp.h, include/editor/medmisc.h, include/editor/medrobot.h, include/editor/medsel.h, include/editor/medwall.h, include/editor/objpage.h, include/editor/seguvs.h, include/editor/texpage.h, include/makesig.h, include/ui.h, main/bm.c, main/bm.h, main/cntrlcen.c, main/cntrlcen.h, main/fuelcen.c, main/fuelcen.h, main/gamemine.h, main/gamesave.c, main/gamesave.h, main/menu.c, main/switch.c, main/switch.h, main/wall.c, main/wall.h, misc/strutil.c, ui/button.c, ui/checkbox.c, ui/file.c, ui/gadget.c, ui/inputbox.c, ui/keypad.c, ui/keypress.c, ui/keytrap.c, ui/lfile.c, ui/listbox.c, ui/menu.c, ui/menubar.c, ui/message.c, ui/mouse.c, ui/popup.c, ui/radio.c, ui/scroll.c, ui/ui.c, ui/uidraw.c, ui/userbox.c, ui/window.c: Copy lots of editor stuff from d2x-rebirth to d1x-rebirth, getting it to work on Mac OS X arch/carbon/conf.h: Disabling IPv6 support for OS X since in Snow Leopard it's buggy, making all Multiplayer pretty much impossible - re-activating soon as proper patches from Apple are in sight 20101223 -------- main/net_udp.c, main/net_udp.h: Reworked object sending/receiving to work without unnecessary type casting and a bit less error prone; Also increased UDP max packet size to 2048 so we can send 7 objects per frame main/credits.c: Align timer_delay for credits so the song (midi or redbook) should at least be heard once 20101222 -------- arch/sdl/window.c: In window_close() prev window did not get EVENT_WINDOW_ACTIVATED but the recent closed window got it causing previous window not being activated anymore and a bunch of memory errors arch/ogl/ogl.c, include/ogl_init.h, main/ai.c, main/ai.h, main/aipath.c, main/aistruct.h, main/collide.c, main/controls.c, main/fuelcen.c, main/game.c, main/game.h, main/gamecntl.c, main/gameseq.c, main/gauges.c, main/laser.c, main/lighting.c, main/mglobal.c, main/multi.c, main/multi.h, main/multibot.c, main/net_ipx.c, main/net_udp.c, main/newdemo.c, main/object.c, main/object.h, main/player.c, main/player.h, main/playsave.c, main/playsave.h, main/powerup.c, main/state.c, main/state.h, main/weapon.c: Made GameTime to GameTime64 using fix64; Changed all structures saving GameTime64 for internal timer purposes to store fix64 and added converting functions to save such times in fix; For Savegames/Demos always reset GameTime64 to 0 while saving and putting all timer values to safe limits, Multiplayer objects are sent in similar fashion main/game.c: Use game_init_render_buffers for editor (for now), fixing crash main/collide.c, main/object.c, main/object.h, main/state.c: added hitobj_list to struct laser_info to get a bit cleaner code main/multi.h, main/net_udp.c, main/net_udp.h: in IPv6 builds also send regular broadcast packets to get games found via LAN between IPv4 clients/systems and IPv6 clients/systems; rather than identifying (lite_info) games via IP use randomly generated GameID and game name to prevent duplicated coming from IPv6 builds main/gamecntl.c, main/net_udp.c: Fix warning for deliberate GameTime64 wrap; uncomment multi_object_to_object_rw and multi_object_rw_to_object prototypes ui/window.c: Put event_process() in ui_mega_process(), hopefully getting editor to (mostly) work (not on Mac yet) 20101211 -------- arch/include/key.h, arch/include/mouse.h, arch/sdl/event.c, arch/sdl/joy.c, arch/sdl/key.c, arch/sdl/mouse.c, arch/sdl/rbaudio.c, arch/sdl/timer.c, editor/ehostage.c, editor/medrobot.c, editor/medwall.c, include/maths.h, include/timer.h, include/ui.h, main/automap.c, main/console.c, main/digiobj.c, main/fireball.c, main/game.c, main/inferno.c, main/kmatrix.c, main/laser.c, main/laser.h, main/lighting.c, main/menu.c, main/multi.c, main/multi.h, main/multibot.c, main/net_ipx.c, main/net_ipx.h, main/net_udp.c, main/net_udp.h, main/newmenu.c, main/scores.c, main/titles.c, ui/listbox.c, ui/mouse.c, ui/scroll.c, ui/window.c: Introduced new data type fix64 to be used for new timers which can last 4462756 years instead of 9 hours; Introduced new timer functions to update and query program time; Used new timer all over the program except GameTime (which comes next) 20101221 -------- d1x-rebirth.xcodeproj/project.pbxproj, editor/med.c, main/menu.c: Activate EDITOR for Mac OS X in Xcode, d1x target; fix some warnings and errors but it won't compile yet 20101205 -------- arch/carbon/messagebox.c, arch/include/window.h, arch/linux/messagebox.c, arch/sdl/key.c, arch/sdl/mouse.c, arch/sdl/window.c, arch/win32/messagebox.c: Add CON_DEBUG level con_printf's for basic events (not EVENT_IDLE or EVENT_DRAW though) 20101204 -------- main/bmread.c, main/piggy.c: When setting a bogus sound in gamedata_read_tbl, don't let piggy_close free it. Fixes freeing of non-malloc'd pointer for PC shareware data main/gamecntl.c: When calling do_game_pause do not allocate msg in Game mod GM_MULTI as it's not used nor freed include/pstypes.h: Changed another WIN32 to _WIN32 to avoid accidentially compiling with WORDS_BIGENDIAN when using VisualC 20101203 -------- main/net_udp.c: Made resent_delay for net_udp_noloss_process_queue() a bit longer depending on the player's ping 20101130 -------- include/hmp.h, misc/hmp.c: Little fixes for rev939 - changed definition from WIN32 to _WIN32, added little hack for incorrectly set HMP loop in Descent2-version of descent.hmp SConstruct, arch/include/messagebox.h, arch/win32/messagebox.c, main/inferno.c, misc/error.c: Add support for Windows native error/warning boxes; Only print to stdout on Linux/other *nix; Fixed redundant printing of Error and Warning via stdout arch/carbon/messagebox.c, main/inferno.c, main/titles.c: Turn fullscreen off when showing a messagebox for Mac; move songs_play_song(SONG_TITLE) from inferno.c to titles.c d1x-rebirth.xcodeproj/project.pbxproj: Change Mac OS X 'Development' SDK to the built-in one to get rid of depreciated 'ShowCursor' warning main/inferno.c: When Quitting is called in standard_handler disable Autodemo if active 20101128 -------- main/multi.c: In multi_new_game when initializing Players structures, also correctly init connected variable which is highly important for spreading pdata to clients and should be set correctly anyways (Thanks to Gold Leader and Flip for help with debugging/testing recent Multiplayer bugs) main/powerup.c: in do_powerup added check for distance of other players to powerup object to make redundant pickups less likely arch/carbon/messagebox.c, arch/include/messagebox.h, arch/linux/messagebox.c, arch/sdl/rbaudio.c, arch/win32/messagebox.c, d1x-rebirth.xcodeproj/project.pbxproj, editor/med.c, main/game.c, main/inferno.c, SConstruct: Add support for OS native error/warning boxes, only implemented for Mac for now main/inferno.c: Fix for r936 - re-added playing titles song when titles are about to show SConstruct: Added missing brackets gone missing in r936 arch/sdl/digi.c, arch/sdl/digi_mixer_music.c, include/hmp.h, main/digi.h, main/songs.c, misc/args.c, misc/hmp.c: Large improvement for _WIN32 native MIDI code by TURRICAN: supprt for HMP track loop, seamless song looping, GS reset, pausing/resuming midi, volume control for each MIDI channel; Set GameArg.SndDisableSdlMixer automatically if compiled without SDL_mixer support; On _WIN32 play HMP natively again 20101126 -------- include/physfsx.h, main/inferno.c, misc/physfsx.c: Implemented PHYSFSX_checkSupportedArchiveTypes to check if essential archive types are supported. Print warnings if not and stop program if necessary. Also added PHYSFSX_listSearchPAthContent to print out search path contents (figures) each time the function is called. Doing this before main HOG inits as well after sucessfully adding archives. Made PHYSFSX_addArchiveContent a bit more verbose as well. main/console.c, main/inferno.c: If -verbose or -debug is set, write gamelog.txt unbuffered for a higher chance to get messages there in case of a crash; Totally supress messages in stdout/err.txt on _WIN32 20101123 -------- main/net_udp.h: reducing max buffer size of an UDP packet from 1024 to 576 bytes - should prevent possible turncating, especially when sending obejcts where max size is actually used main/net_ipx.c, main/net_udp.c: When verifying objects, do not necessarily check for controlcen as it's not necessarily there in some anarchy missions 20101122 -------- arch/sdl/jukebox.c: Make sure read_m3u won't read past the end of the buffer, causing a crash main/inferno.c: If it can't find descent.hog, still print some useful info 20101121 -------- arch/sdl/jukebox.c, include/physfsx.h, main/menu.c, misc/physfsx.c: Created function PHYSFSX_isNewPath to check wether given path has already been added to Searchpath or not; Used PHYSFSX_isNewPath for menu browsing code instead it's own implementation; Using PHYSFSX_isNewPath for Jukebox directory, too to make sure Jukebox will not accidentially remove Game content depending on user selection; Also only keep Jukebox directory added until files are stored to prevent any other file present in this path can override or add anything to the game main/config.c: For fresh configuration set Redbook music as default for Mac, Builtin music for all others main/hud.c: When checking for redundant messages in HUD display, compare new message to most recent one for locking and check whole list only for messages marked with HM_REDUNDANT. This will show all messages in correct order while keeping redundancy-prone messages from looping infinitely 20101113 -------- main/playsave.c: In plyr_save_stats setting filename to size of PATH_MAX to have enough space to also hold the player directory prefix which would otherwise create a memory corruption and crash the game 20101109 -------- main/multi.c: In multi_consistency_error check for Game_wind before trying to set it in/visible - just for safety mem/mem.c: When running out of memory slots, do not try to print detailed info as it will only call a negative array index 20101101 -------- main/newmenu.c: In case listbox strings are too long for screen, fit box width to screen width, shorten strings and add a scroll effect to selected item main/titles.c: Increased buffer for fname2 in load_briefing_screen, preventing buffer overflow in case replacement filenames are longer than DOS-style 20101030 -------- main/titles: Make songs playing at end briefings loop, like they used to in the original game main/menu.c: Text string for level music was made smaller some time ago so BROWSE_TXT_SHRT basically became obsolete - removed it now and show BROWSE_TXT instead 20101029 -------- arch/sdl/digi_mixer_music, include/hmp.h, misc/hmp.c: Instead of writing converted MIDI to file, write to buffer so it can be played directly 20101016 -------- main/custom.c, main/gameseq.c: Finished support for custom textures and robots, fixed some bugs, reformatted code and placed function calls to properly work for designated mission/level D1X.make, arch/sdl/jukebox.c, d1x-rebirth.xcodeproj/project.pbxproj, include/pstypes.h, main/hud.c, main/menu.c, main/newdemo.c, main/titles.c, misc/args.c, misc/physfsx.c: Fix errors for Mac OS 9, Mac OS X 'd1x' target builds again 20101014 -------- main/menu.c: Fixed compilation of menu.c when USE_SDLMIXER is not defined arch/sdl/jukebox.c, include/cfile.h, main/console.c, main/hud.c, main/menu.c, main/mission.c, main/net_ipx.c, main/net_udp.c, main/scores.c, main/titles.c, misc/physfsx.c: Added format arguments to all printf, sprintf and snprintf calls missing them to prevent warnings/errors with some distributions of gcc 20101010 -------- d1x-rebirth.xcodeproj/project.pbxproj, INSTALL.txt: Use dynamic PhysicsFS library again to fix linking errors 20100926 -------- arch/sdl/jukebox.c, include/strutil.h, main/menu.c, misc/strutil.c: Add support for M3U playlists, tweak 'Jukebox playing' message so it shows the end of the path when truncating 20100925 -------- include/cfile.h, include/physfsx.h, main/bmread.c, main/piggy.c, misc/physfsx.c: Add 'Data' subdir as a searchpath, simplifying a lot of file opening/checking/closing code misc/physfsx.c: fullpath variable was missing for _WIN32 20100919 -------- main/state.c: Pass -1 instead of 255 as the colour to ogl_ubitmapm_cs when drawing savegame previews, to make sure a black rectangle isn't drawn instead iff/iff.c, main/titles.c: To fix Dravis's head in endgame debriefing, don't remap the colours and read compressed .bbm bitmaps properly (both my bad) 20100917 -------- arch/carbon/conf.h: Enable IPv6 for Mac OS X main/config.c: Set default Jukebox music paths to original Redbook music in iTunes for Mac OS X d1x-rebirth.xcodeproj/project.pbxproj, include/cfile.h, include/hmp.h, include/physfsx.h, INSTALL.txt, main/config.c, main/inferno.c, main/newdemo.c, main/newmenu.c, main/playsave.c, misc/hmp.c, misc/ignorecase.c: Link to PhysicsFS static library and use header from source for Mac OS X main/menu.c: Put in a note that a restart is required when changing the texture filter level (remove later when it isn't) d1x-Info.plist, d1xgl-Info.plist, English.lproj/InfoPlist.strings: Increment version to 0.56.0 for Mac OS X, marking release point 20100904 -------- main/titles.c: In briefing_init() init robot angles properly because in show_spinning_robot_frame() robot_angles.h is incremented only but not initialized main/game.c, main/game.h, main/gameseq.c, main/state.c: Removed Fusion_last_sound_time and made Fusion_next_sound_time static inside FireLaser() with it's own fallback function for bogus timer values - should make this code insusceptible against errors - last but not least: minus two globals 20100903 -------- main/game.h, main/gameseq.c, main/state.c: Reset Fusion_next_sound_time in init_player_stats_level() to hopefully fix Fusion not doing damage or playing sounds 20100902 -------- arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, d1x-rebirth.xcodeproj/project.pbxproj, main/multi.h: On Mac OS X - no longer have to copy SDL_mixer.h to SDL framework; frameworks can now be in /Library/Frameworks; fix for obscure compile error involving u_int32_t include/ogl_init.h, 2d/font.c, arch/ogl/ogl.c, arch/ogl/gr.c: Rewrote code to control Texture Filtering a little so it's easier to apply Mipmaps for different parts of the game independently main/gamecntl.c, main/menu.c, main/newdemo.c, main/newdemo.h: Using PHYSFSX_findFiles to make sure random demo playback will only find actual demo files and not quit autodemo; added DEMO_EXT for an universal definition of demo file extension arch/sdl/digi_mixer_music.c: When opening music file via filehandle, made sure buffer is freed after playing to prevent major memory leakage 20100901 -------- main/net_ipx.c, main/net_udp.c: in pdata communication swap_bytes was set for create_shortpos causing problems on PPC architecture; in multiplayer host menu set citem to START GAME by default 20100831 -------- include/u_mem.h, main/menu.c, main/newmenu.c, main/newmenu.h: Added feature to let select_file_reursive() change drive on _WIN32 via CTRL-D; Removed second definition of MEM_K accidentially happened due to bad communication 20100828 -------- main/menu.c: In list_dir_el make sure PHYSFS_getRealDir won't give NULL to strcmp which will happen for files located in a Windows root directory include/u_mem.h: Make define of MEM_K apply to non-debug builds as well (whoops) main/menu.c: In select_file_recursive handle paths relative to the current write directory correctly 20100827 -------- arch/include/jukebox.h, arch/sdl/jukebox.c, include/u_mem.h, main/menu.c: Add path browsing feature to make song file/directory selection easier include/u_mem.h, main/menu.c: Moving upwards definition of MEM_K so it's not restricted to !NDEBUG; Initialized **i in list_dir_el properly to silence gcc when compiling main/menu.c: In select_file_handler properly initialize newpath preventing memory errors and crashes 20100825 -------- main/titles.c: Made loading of Hires briefings a bit more simpler (more D2-ish) and not using a new briefing_screen structure; Also perform a check if requested image originates from descent.hog or a third-party mission and do not load a Hires version in the latter case 20100824 -------- main/mission.c, main/mission.h, main/titles.c: Overhauled detection of TEX/TXB files for Briefings and Endings 20100822 -------- main/net_ipx.c, main/net_udp.c: Moved levelnum-sanity-check in game_param_handler so it will be checked when screen is changed to allow entry of secret levels; added menu item START GAME for consistency and added proper subtitle for game setup page INSTALL.txt: Added link for the Mac Content Sound Effects AddOn Pack arch/sdl/digi_mixer_music.c: Use more reliable Mix_LoadMUS for music in directory searchpaths, so WAVE's and MP3's are correctly loaded (probably others) 20100821 -------- d1x-rebirth.ico, d1x-rebirth.xpm, arch/sdl/gr.c, arch/ogl/gr.c: Bind WM-Icon to application SConstruct, d1x-rebirth.bmp, d1x-rebirth.xpm, arch/sdl/gr.c, arch/ogl/gr.c, arch/win32/d1xr.res: Added res-file to be linked in Windows build to show icon in Filemanager; converted icon file to be smaller 20100819 -------- d1x-rebirth/main/bmread.c, d1x-rebirth/main/paging.c, d1x-rebirth/main/aipath.c, d1x-rebirth/main/piggy.c, d1x-rebirth/main/gamesave.c, d1x-rebirth/main/dumpmine.c, d1x-rebirth/main/kconfig.c, d1x-rebirth/main/gamecntl.c, d1x-rebirth/editor/segment.c, d1x-rebirth/editor/kmine.c, d1x-rebirth/editor/mine.c, d1x-rebirth/editor/group.c, d1x-rebirth/editor/med.c, d1x-rebirth/editor/eswitch.c, d1x-rebirth/editor/medwall.c, d1x-rebirth/iff/iff.c, d1x-rebirth/ui/radio.c, d1x-rebirth/ui/scroll.c, d1x-rebirth/ui/window.c, d1x-rebirth/ui/keypad.c, d1x-rebirth/ui/file.c, d1x-rebirth/ui/listbox.c, d1x-rebirth/ui/mouse.c, d1x-rebirth/ui/menubar.c, d1x-rebirth/ui/lfile.c, d1x-rebirth/mem/mem.c: Patching together editor so it compiles again (while still not running); Implemented PhysFS for file accessing for editor- and debugging-related code main/text.c: In demo list help text changed string CTRL+C to CTRL-C for consistency main/songs.c, arch/sdl/digi_mixer_music.c, arch/sdl/rbaudio.c, arch/sdl/digi.c: For each Music playback system defining own volume scaling definition which was wrong for SDL_mixer 20100817 -------- main/digi.h, main/menu.c, main/songs.c, main/songs.h: Renamed MUSIC TYPE options BUILT-IN MUSIC to BUILT-IN/ADDON MUSIC and CUSTOM MUSIC to JUKEBOX; Removed LEVEL-DEPENDENT play order for Jukebox as this is now mainly covered by AddOn packs and future M3U-support 20100816 -------- main/net_ipx.c, main/net_udp.c: When switching from COOP to any other game mode, make sure Netgame.max_numplayers, MaxNumNetPlayers as well as the menu text showing the player limit is updated correctly INSTALL.txt: Updated docs to add new OGG Soundtrack created by Brandon Blume main/inferno.c: Moved up PHYSFSX_addArchiveContent() a little inside main() so -debug and -verbose will show us this content which will be helpful for debugging possible problems with AddOn Zips 20100815 -------- INSTALL.txt, include/physfsx.h, main/inferno.c, misc/physfsx.c: Added support to automatically load/mount ZIP files at startup, giving option to dynamically override or replace game content; Updated docs 20100814 -------- main/game.c: Tidy up for EVENT_IDLE case in game_handler, hopefully fixing obscure 'optimise threads' bug 20100812 -------- main/weapon.c: When picking up laser, game would show generic weapon pickup/already-have messages instead of laser-upgrade/maxed-out messages only - fixed 20100811 -------- main/laser.c: The inital vector scaling to compensate previous frame-skipped tracking was not aligned to FrameTime. Removed that code and just divided homer_turn_base values to compensate this offset properly. Thanks to zif for hinting me to that; Added comment about the how and why of the homing missile scaling issue 20100809 -------- d1x-rebirth.xcodeproj/project.pbxproj, include/physfsx.h, include/pstypes.h, misc/physfsx.c, SConstruct: Add 'Resources' in .app bundle to searchpath for Mac; move bigger functions from physfsx.h to physfsx.c; resolve conflict with definition of 'bool' include/pstypes.h: Cleaned and simplified includes to fix possible and actual problems with PATH_MAX 20100806 -------- arch/sdl/event.c: Between event sending, exit event_process if front window is different, fixing netgame joining problem introduced with commit on 20100731 20100803 -------- main/hud.c: When updating redundant HUD messages check the for-loop not the start with a negative number - causes too long message display and negative array index 20100801 -------- main/menu.c, main/songs.c, main/songs.h, main/gameseq.c, main/digi.h, arch/sdl/digi.c: Builtin music list now dynamically allocated and not limited to 30 songs; Instead of never loading new level when loading savestate ingame, only do this for Redbook and Custom Music playing order 'continously'; if no endlevel song is specified in Custom Music continue with level music arch/sdl/mouse.c: If mouse_toggle_cursor is set to activate, do not toggle ursor visibility as mouse_update_cursor_and_grab might decide it should be hidden 20100731 -------- main/inferno.c, main/kmatrix.c, main/menu.c, main/newmenu.c, main/newmenu.h, main/scores.c: For polling newmenus, set rval using a pointer and don't delay closing the window, hopefully fixing bad memory access when clicking in level scores screen; change newmenu_close to newmenu_free_background to avoid confusion 20100730 -------- SConstruct: restricted parsing of sdl-config to *NIX and Mac builds as it's static on Win32 anyways; added verbosebuild as SCons option to print out all compiler/linker messages main/state.c, main/game.c, arch/sdl/event.c, arch/sdl/mouse.c, arch/include/event.h: Added event_flush to take place in game_flush_inputs which will clean SDL events which may be buffered while event_process was suspended; suspend Game_Wind while loading restoring save state while playing a level to properly flush controls and reset timer; when toggeling cursor, also directly modify the mouse to wanted behaviour instead of waiting for mouse_update_cursor_and_grab 20100729 -------- main/automap.c, main/fuelcen.c, main/game.c, main/gamecntl.c, main/gameseq.c, main/menu.c, main/newmenu.c: Tidy up use of set_screen_mode arch/ogl/gr.c, arch/ogl/ogl.c: Using rather sane values for gluPerspective - fixing Z-Fighting bugs on Intel chips; in Fullscreen toggle, always apply new viewing values independent of Screen_mode 20100728 -------- main/automap.c, main/game.c, main/gamecntl.c, arch/sdl/init.c, arch/sdl/mouse.c, arch/include/mouse.h: One more take on Mouse cursor friendliness: Merged mouse_toggle_cursor and mouse_toggle_grab; instead of trying to use SDL_GetAppState (which does not work as expected on Windows) to release mouse, use strict calls of mouse_toggle_cursor so we at least have a free mouse outside of Game_wind and Automap; decreased time to automatically hide cursor; added mouse_close to release mouse in case of emergency 20100727 -------- 2d/pcx.c, include/pcx.h, main/cntrlcen.h, main/effects.c, main/fireball.c, main/fuelcen.h, main/gameseq.c, main/kmatrix.c, main/net_ipx.c, main/net_udp.c, main/render.c, main/segment.h, main/switch.c: Show main menu background for died in mine messagebox; equalise fuelcen.h and cntrlcen.h arch/sdl/mouse.c: Fixing automatic mouse release function - still this does not seem to work in every case misc/hmp.c: Fixing bug in MIDI header - format was written in size of int instead of short arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, main/config.c: Moved digi_set_digi_volume call from config loading to designated audio subsystem init function so it will be correctly set after the sound system is auctionlly initialized 20100726 -------- arch/sdl/event.c, arch/sdl/mouse.c: Overhauling showing/grabbing cursor and also taking care of case if program looses focus; store old_delta_x/y in mouse info structure 20100725 -------- arch/sdl/event.c, arch/ogl/gr.c, arch/sdl/gr.c: Exit SDL_PollEvent early if window changes, to avoid menu problems when pressing keys fast; fix 'condition is always false' warning main/inferno.c, main/inferno.h: Rewrite quit system, fixing *many* bugs with it :P main/newmenu.c: For menus, only call the user function for closing immediately before closing, fixing memory errors when the user function frees memory main/newmenu.c: Fix crash caused by last commit (whoops) 20100721 -------- main/net_udp.c: Fixing crash when joinging game over UDP Netlist: when exiting the menu for any reason, return 0 instead of following the code and possibly lead to drawing text from a newly free'd pointer - D'OH! 20100720 -------- main/net_udp.c: Thanks to Marix for hinting me I should not init a pointer with quotes if I plan to allocate/free it... my stupid-level officially broke the record 20100719 -------- misc/hmp.c: Did not close hmp after MIDI conversion which caused some unfree memory - fixed main/gameseq.c, main/state.c, main/state.h: Introduced state_quick_item so we can safly check if there is a valid quicksave slot wihtout messing around with state_Default_item which is supposed to always show a valid slot in the first place main/titles.c: In briefings make sure Current_color cannot exceed possible array bounds include/strutil.h, main/credits.h, main/menu.c, main/bmread.c, main/newdemo.c: Fixing some harmless compiler warnings caused by missing includes, missing newlines at end of file; cleaned up strutil.h arch/win32/ipx.c: Removed redundant Winsock calls from Windows-specific IPX code - it's already in net_ipx.c 20100718 -------- SCsonstruct, d1x-rebirth.xcodeproj, arch/sdl/digi.c, arch/sdl/digi_mixer_music.c, include/cfile.h, include/hmp.h, include/hmp.c: Merged all HMP-related code into hmp.c/h; Also introduced new HMP to MIDI conversion functions based on JJFFE which use former Win32-related HMP-code - fixes some bugs in MIDI conversion and cleaner 20100717 -------- main/gamesave.c, main/render.c: Removed OGL hack to fix overlapping room in D1 lvl19 and rather move vertex a little. Still a hack but now without messing Depth test main/gameseg.c, main/render.c: Instead of screwing by possibly using negative array indicies in find_seg_side() return -1. In ordering segments make this result in unimportant order; Taking in some Asserts which were disabled years ago by me. Let's fix this for real when we get to it main/game.c, main/gamecntl.c: Implenented POBOYS cheat as equivalent to D2's DELSHIFTB arch/sdl/digi_audio.c: For normal digital audio (11/22Khz) use buffer of 1024 for all platforms to prevent delay 20100716 -------- main/gamecntl.c: Fixing showing options menu in demos - was still called (or rather not) by obsolete variable main/newmenu.c, main/newmenu.h, main/automap.c, main/game.c, main/kconfig.c, arch/sdl/event.c, arch/sdl/joy.c, arch/sdl/init.c, arch/sdl/key.c, arch/sdl/mouse.c, arch/include/mouse.h: Only use one single call of timer_get_fixed_seconds() for whole SDL event loop; Abstracted grabbing mouse and mouse cursor toogle to mouse functions instead of calling SDL functions inside of non-arch code; Automatically hide mouse cursor if it's not used for more than 3 seconds; Reworked placement of mouse grabbing toggle; Do not read any mouse input if -nomouse is given main/newdemo.c: If newdemo_start_playback fails if random file is given set -autodemo to 0 to prevent endless loop 20100715 -------- main/wall.c, main/newdemo.c, main/newdemo.h, main/gauges.c: Cleaned the variables used for newdemo code; Instead of giving both old and new values to special recording functions, added new variables to demo code serving this purpose and also checking for redundant record calls which only would waste bytes; Removed duplicated-object-id-hack which did not work as expected and caused jittering on playback; In that process, found a bug where Num_open_doors might nor be set correctly - cleaned that up a little and got also rid of one aweful goto main/titles.c: Scale tab stops in briefings to font-size correctly main/titles.c: Make sure the right canvas is set for titles and briefings, fixing bug where briefing is shown in the cockpit when using 'farmerjoe' cheat 20100713 -------- include/args.h, main/net_udp.c, main/collide.c, main/multi.c, main/inferno.c, main/object.c, main/wall.c, main/state.c, main/hud.c, main/weapon.c, main/hostage.c, main/hudmsg.h, main/newdemo.c, main/net_ipx.c, main/fuelcen.c, main/ai.c, main/endlevel.c, main/powerup.c, main/game.c, main/gauges.c, main/gauges.h, main/gamecntl.c, misc/args.c, d1x.ini, arch/ogl/gr.c, arch/sdl/jukebox.c: Added expandable classes for HUD messages (like D1X but slacked) to better handle Multi messages or redundant messages; Rewrote HUD code completely; Changes -playermessages to -multimessages since this is more appropriate; Removed remnants of -mprofile 20100709 -------- main/mission.c: When reading mission file, check for sanity of possible breifing or ending to make sure author did not just screw up the file main/laser.c: Trying to improve reliability to find appropriate homing object by using vm_vec_mag/normalize instead of their *quick equivalents; Removed code which supposedly meant to track objects near reticle - don't like that 20100708 -------- main/net_udp.c, main/net_udp.h: Reworked handling of Netlist now also showing full game info; Prevent Clients from sending lite_info; Make lite_info show numconnected instead of numplayers as this would show disconnected ones as well; Removed reusing ports on different instances in Windows build - only screws up several games running on one machine main/game.c, main/gameseq.c, main/multi.c, main/net_udp.c, main/net_ipx.c: Improved hanlding for closing sockets - doing via closing of Game_wind when available or in specific multi menus; Also handling GM_GAME_OVER setting over Game_wind closing as well if apprpriate - cleaner and helps to cleanup multi when mission is over arch/sdl/key.c: Also send event KEY_COMMAND if there's somethig in our Unicode buffer since not every Unicode key corresponds to a keysym on every layout README.txt: Fixing typo 20100705 -------- main/kconfig.c: Fixing issue when assigning mouse button if a citem is still pointed out; Fixing still processing key commands even if we want to assign a key; After setting mouse button, reset mouse state properly arch/sdl/digi_mixer_music.c: Fixing issue introduced in rev1139: Game could of course not open music files which are not inside Searchpath or added to it - re-added playing over absolute path main/net_ipx.c, main/net_udp.c: When selecting coop game mode, make sure that besides max players menu values also actual player number is set and menu text is updated properly main/net_udp.h: Reducing sending objects per frame from 20 to 1 again to reduce possibility of timeout on stressed systems main/songs.c: Fixing building on Windows if SDL_Mixer is not a target 20100704 -------- main/net_udp.c: Fixed Compiler-warning on Windows main/net_ipx.c, main/net_udp.c: Implemented Winsock functions for UDP which I totally forgot about; Now when leaving game in any way, close sockets and Winsock stuff main/gameseq.c, main/multi.c: Since time is not suspended between levels in Multiplayer, call reset_time after level change. Apply this in Singleplayer, too since it should always be safe - and appropriate - to reset timer_value soon as a new level begins main/net_udp.c: Fixes for rev1148: Was too hasty with calling net_udp_close; Fixing typo in WSACleanup() 20100701 -------- 2d/font.c: For gr_get_string_size introduced get_char_width_f to calculate with floats to measure non-integer font scalings; Cleanup main/net_udp.c, main/newmenu.c: Renamed manual_join to direct_join; Aligned letlist tabs a little bit 20100630 -------- main/gameseq.c: If multi_level_sync() fails, restart menu music since level music is playing already main/game.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/newmenu.h, main/weapon.c: Removed SurfingNet global and made tabs a parameter of newmenu_dotiny; Same procedure with MenuReordering which is replaced with newmenu_doreorder to set reordering flag specifically main/net_udp.c: Always try to open UDP default port when discovering Netgames and give warning if that fails; If entered IP address cannot be resoled, do not warn me twice 20100629 -------- main/net_ipx.c, main/net_udp.c: Aligned default width for IPX-Netlist menu to fit possible items a bit better; Fixed two small bugs when sending and receiving lite_info in UDP; Allowed broadcast on UDP sockets (for later use) main/menu.c, main/new_udp.c, main/net_udp.h: Added UDP Netlist to join LAN games discovered/announced via broadcast main/net_ipx.c, main/net_udp.c: Improved handling of multi level sync and exit smoothly back to the menus; Fixed another small bug in lite_info broadcasting which was sending full info; By broadcasting full info, host could cripple Netgame so a new security measure is implemented to protect host from letting his game be overwritten from outside 20100627 -------- main/game.c, main/game.h, main/gameseq.c: When starting, leaving or changing a level in any way, use more ordered approach to set Game_wind visible or invisible. Fixing timer-issues after level-change and makes hiding of Game_wind obsolete for certain messageboxes; Moved GameTime and weapon timer variables out of reset_time since this function is not appropriate for this and is not needed between levels anymore due to window management handling start/stop_time properly arch/sdl/digi_mixer_music.c, main/jukebox.c: For playing music over SDL_mixer always use handle over PhysFS to save the path building mess; When building Jukebox path, only try to build full path if given path is actually a child of Searchpath 20100625 -------- main/gamecntl.c: Implemented kill_and_so_forth via DEL+SHIFT+B for easier debugging 20100624 -------- arch/ogl/gr.c, arch/sdl/gr.c, include/gr.h, main/menu.c: Added function to list valid resolutions and build resolutions menu dynamically with the resulting list main/gamecntl.c: When inregulary exiting a level by warp cheat, suspend Game_wind and reactivate again after the switch 20100623 -------- main/menu.c, main/newmenu.c, main/newmenu.h, main/net_ipx.c: Making menus recreated on the fly in case resolution or font-size changes; Removing arguments to pass width and height to menu which was not used except on one IPX menu; Fixing measurement of menu strings of type NM_TYPE_INPUT_MENU; Fixing slight bug in freeing IPX netlist main/menu.c: If no player exists and GameCfg.LasterPlayer is unset, give user a nice default for convenience and - more important - let menu stop to nag about missing callsign and thereby showing the player creation dialogue over and over again main/newmenu.c: Fix for last rev1130 - store resolution and font-size in matching data type 20100622 -------- main/titles.c: Make sure GAME_FONT is set when reading out briefing text so char dimensions will always be stored correctly 20100620 -------- main/newdemo.c: For starting demo, seperate hide_menus() and game_setup() since between this, demo must load the actual level and it's palette; Fixed small bug in interpolate_frame() causing interpolation happening in very first frame causing file read corruption 20100619 -------- main/titles.c: For briefings, keep elementes of show_briefing_bitmap and show_animated_bitmap in correct aspect main/laser.c: Re-balanced homing-device turn values introduced in rev1118 based on comparisons to many levels played 20100618 -------- 2d/bitblt.c, include/gr.h, main/game.c, main/gauges.c: Introducing gr_bitblt_find_transparent_area to dynamically detect boundaries of sub canvas used for CM_REAR_VIEW; On the way also allowing to create weapon box sub bitmaps from uncompressed cockpit bitmaps include/physfsx.h, main/newdemo.c: Removed PHYSFSX_getFreeDiskSpace and relying on success of buffered writing to see if demo recording must be stopped 20100617 -------- main/weapons.c: If picking up one missile out of a four-pack, use singular description instead of plural main/gauges.c: Fixing regression from rev1038 which broke showing laser level or quadness in cockpit and statusbar 20100615 -------- main/game.c, main/gameseq.c: Resetting GameTime, Next/Last_flare/laser/missile_time in reset_time() together so GameTime-rollover-fallbacks will not create a massive delay when starting a new level main/laser.c: Removed the previously homers code and instead used old one to keep good ol' Gameplay; Removed FrameCount steps from track_track_goal() and scaled homing vector accordingly to this change, including properly scaling it to FrameTime; Made code more similar between D1X and D2X; Introduced different turn rates for different difficulty levels main/game.c: Fixing typo in Netgame help screen arch/sdl/digi.c, arch/sdl/digi_audio.c, main/songs.c: Fixing digi_win32_ functions I broke yesterday. THANKS ZIF! 20100614 -------- include/args.h, include/physfsx.h, main/newmenu.h, main/inferno.c, main/menu.c, main/songs.c, main/songs.h, main/config.c, main/config.h, main/gameseq.c, main/digiobj.c, main/digi.h, main/game.c, main/gamecntl.c, misc/args.c, d1x.ini, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/init.c, arch/sdl/jukebox.c, arch/sdl/digi.c, arch/sdl/digi_audio.c, arch/include/digi_audio.h, arch/include/digi_mixer.h, arch/include/digi_mixer_music.h, arch/include/jukebox.h: Increased SDL_mixer music abilities to play non-hmp from HOGs, having Level-music path to play, options to specify non-level tracks and added various playing order methods; Abstracted SDL_mixer- and Redbook-interfaces; Simplified program flow through all music functions arch/include/window.h: Added missing newline at EOF arch/sdl/jukebox.c: Small fix and improvement for Jukebox path detection arch/sdl/digi_mixer_music.c, main/songs.c: Use strrchr instead of strchr for music filename extension in case there are dots in the filename main/collide.c: Made reactor damage with persistent weapons FPS-independent but still a bit stronger than normal arch/sdl/jukebox.c: rev1112 contd: Killed juggling around with adding Jukebox paths - must always be removed correctly if Jukebox loading fails arch/linux/hmiplay.c, arch/sdl/digi.c, main/songs.c: Process -nomusic argument again 20100503 -------- main/menu.c: Properly specify number of items for do_options_menu, so the options menu actually shows arch/include/event.h, main/newmenu.h: Merge d_event and newmenu_event enum's, hopefully fixing compiler warnings in GCC 4.5.0 arch/sdl/joy.c, arch/sdl/key.c, arch/sdl/mouse.c: Comment out redundant calls to event_poll, fixing rapid bomb dropping bug (and probably others) 20100405 -------- arch/include/digi_audio.h, arch/include/digi_mixer.h, arch/include/digi_mixer_music.h, arch/linux/hmiplay.c, arch/linux/hmistub.c, arch/sdl/digi.c, arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, arch/sdl/rbaudio.c, main/digi.h, main/gamecntl.c, main/songs.c, main/songs.h, main/titles.c: Actually play endgame music when game is finished main/gameseq.c: No restarting music when reloading a saved game 20100404 -------- arch/include/event.h, arch/sdl/event.c, main/automap.c, main/game.c, main/gamecntl.c, main/gameseq.c, main/inferno.c, main/inferno.h, main/menu.c, main/multi.c, main/net_ipx.c, main/net_udp.c, main/newdemo.c, main/state.c, misc/error.c: Get rid of a heap of uses of Function_mode, quit properly (freeing all windows and asking for confirmation for game) when clicking close box arch/include/window.h, arch/sdl/window.c, main/inferno.c, main/menu.c, main/mission.c, main/net_ipx.c, main/net_ipx.h, main/net_udp.c, main/net_udp.h, main/newmenu.c: Make menus for hosting a netgame stack, make quitting work with newmenu_do2 and simpler 20100403 -------- arch/sdl/mouse.c, main/game.c, main/net_ipx.c, main/net_ipx.h, main/newmenu.c, main/newmenu.h, main/state.c: Make newmenu_do3 and newmenu_dotiny return as soon as the newmenu is created, which will allow the main menu (and others) to persist main/menu.c: Make main menu persist to streamline redrawing (later) main/kconfig.c, main/menu.h, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/scores.c: Remove calls to nm_draw_background1 to show newmenus stacked main/menu.c, main/newmenu.c, main/scores.c: Move copyright drawing to main menu's event handler for tidiness 20100402 -------- arch/include/event.h, arch/sdl/event.c, arch/sdl/key.c, arch/sdl/mouse.c, main/automap.c, main/credits.c, main/game.c, main/gamecntl.c, main/inferno.c, main/kconfig.c, main/kmatrix.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/scores.c, main/titles.c: Add a default event handler for screenshots, entering debugger, Redbook repeating etc main/menu.c, main/newmenu.c: Keep demo selector just after playing one, for convenience 20100331 -------- main/game.h, main/gamecntl.c, main/gamerend.c, main/kconfig.c, main/kconfig.h, main/laser.c, main/laser.h: Make gamecntl.c more similar between D1X and D2X main/game.c, main/gamecntl.c, main/multi.c, main/multi.h: Make game respond to EVENT_KEY_COMMAND for key commands, allowing default key handler (later) 20100330 -------- main/titles.c: Fix black and white swapping when viewing robots in briefings using Mac data 20100328 -------- main/lighting.c: For casting light from Player-object, smooth out thrust to prevent flickering on high FPS 20100327 -------- main/kmatrix.c, main/net_udp.c: Initialise 'playing' to 0 for UDP kmatrix, making sure player progresses to next level; always return 1 when starting to join a UDP game so it doesn't immediately return to the main menu main/gameseq.c, main/menu.c: Hide mission dialog before the level intro screens are shown, make sure it doesn't try to show it again after it was closed - fixing bad memory access main/game.c: Finally fix bug where if you start a single player game then a multiplayer game, time is stopped. Always start time if it's stopped and the game window is activated main/menu.c: Check menus[0], not menus[i] in hide_menus - fixing possible crash main/gameseq.c: In AdvanceLevel only set Game_mode to GAME_OVER if current level is last level, fixing stupid mistake introduced in rev. 1080 main/gameseq.c: Make sure correct palette is loaded for game, fixing swapping of black and white and cockpit/status bar not showing for ogl build, in multiplayer 20100326 -------- main/endlevel.c, main/gameseq.c, main/mission.c, main/mission.h, main/titles.c, main/titles.h: In Endlevel sequence, re-align big explosion to draw in front of exit model, relative to viewer; Re-organized tex files for Briefings and Endings and created more general code to play them; Re-aligned Dravis' head main/automap.c, main/gamecntl.c, main/kconfig.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/scores.c: Make all windows except game and editor use EVENT_KEY_COMMAND, returning 1 if handled; pass NULL instead of userdata for the PCX filename, for newmenu_do1 include/cfile.h, include/physfsx.h: Ignore case-sensitivity for cfile_init/close/size and PHYSFSX_openReadBuffered main/titles.c: Fixing uninitialized angles for robots in briefings 20100324 -------- arch/include/event.h, arch/include/mouse.h, arch/sdl/mouse.c, main/kconfig.c, main/movie.c, main/newmenu.c, main/titles.c: Add EVENT_MOUSE_BUTTON_DOWN and EVENT_MOUSE_BUTTON_UP, use for all windows except game and editor. Fixes crash on iMac G5 when pressing keys to progress through briefing main/titles.c: Only show briefing background if we have one (which we should always for Descent 1) 20100322 -------- main/credits.c: Make credits screen a window main/titles.c: Make title screen a window. Only the editor left now... 20100321 -------- main/gameseq.c, main/multi.c: Hide game window between levels main/multi.c: Fix bug introduced in last commit - when the last level is finished, hide the game window - making sure the cockpit isn't drawn over the kmatrix screen 20100320 -------- main/cntrlcen.c, main/fuelcen.c, main/fuelcen.h, main/game.c, main/gamecntl.c, main/gamerend.c, main/kmatrix.c, main/multi.c, main/multi.h, main/net_ipx.c, main/net_udp.c, main/newdemo.c, main/state.c: Make kmatrixs into windows, rename Fuelcen_seconds_left to Countdown_seconds_left for consistency main/game.c: Fix bug - make sure time isn't stopped for multiplayer when aborting, so starting a second game doesn't result in a frozen game 20100317 -------- main/menu.c, main/menu.h: Add hide_menus and show_menus (for later use in the case of D1X) main/titles.c: Make briefing into a window, allowing more flexibility with other windows and tidying code up main/game.c, main/menu.c, main/mission.c, main/mission.h, main/net_ipx.c, main/net_ipx.h, main/net_udp.c, main/net_udp.h, main/newmenu.c, main/newmenu.h: Make all listboxes fall back to main event loop for flexibility 20100317 -------- arch/sdl/window.c, arch/include/window.h: Add window_exists function so event loops can be placed for specific windows 20100313 -------- main/newmenu.c: Fix memory error for listbox when clicking in the region where there are no items 20100310 -------- main/titles.c: Put most local variables in show_briefing in 'briefing' struct, to make briefing a window in future 20100309 -------- main/titles.c: Put briefing globals in 'briefing' struct, pass this by parameter arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c: Change audio buffer size back to 1024 for Mac only - fixing crackly music main/titles.c, main/titles.h: Put parameters in functions from do_briefing_screens to show_briefing in 'briefing' struct, to make briefing a window in future 20100304 -------- main/piggy.c, main/text.c, main/text.h: Fixed some Piggy- and Text-loading routines for Shareware, Destination Saturn and 1.0 Registered; Full support for End-Briefing on non-registered still missing however main/mission.c: Init variables/strings at the beginning of load_mission() to prevent errors if demo content is used main/laser.h: If Shareware content is used, fallback to original Smart behaviour since Shareware content has no own definition for Bot-related Smarts 20100303 -------- arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c: Changed default Audio-buffer size to 2048 bytes. Should prevent crackly playback on some systems debian/control: Adding scons to depends-list for Debian packaging 20100301 -------- main/gameseq.c, main/inferno.c, main/state.c, main/titles.c, main/titles.h: Make titles.c more similar between D1X and D2X 20100227 -------- main/menu.c: Actually change to MIDI if Jukebox was selected arch/sdl/jukebox.c: No more crashing if an invalid Jukebox path is entered - default to MIDI 20100226 -------- main/menu.c, main/newmenu.c: Handle all user input in callback for sounds menu, being more judicious about when to restart the music. Also make the jukebox path input a NM_TYPE_INPUT_MENU, allowing the user to abort changes 20100225 -------- main/game.c, main/gamecntl.c, main/gameseq.c, main/state.c, main/state.h: Put fast save back, using Alt-F1 instead of F6 arch/sdl/key.c: Move call to callback outside of loop in key_handler, now deleting a second demo using CTRL-D actually works main/automap.c, main/game.c, main/gamecntl.c, main/gauges.c, main/kconfig.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/scores.c: Call game_flush_inputs for all windows' EVENT_WINDOW_ACTIVATED, so clicking on a pilot doesn't bring up the multiplayer screen for example main/kconfig.c: Resetting menu->mouse_state after changing a key in kconfig so you will not accidentially activate a new field when left mouse button is assigned 20100224 -------- main/kconfig.c: Due to the change of GameCfg.ControlType, Mouselook was broken - fixed 20100223 -------- SConstruct: Removing svnmicro as micro numbering option since SVN-revisions will not really represent logical numbering; Some cleaning for libs usage; Small cleanup SConstruct, main/multi.h, main/net_udp.c, main/net_udp.h, main/vers_id.h: Make Version-check for UDP also cover Micro-versions; Making sure versioning will act same way as conf.h for MacOS main/game.c: Add to help how to send a message to a specific player in Multiplayer main/songs.c: Adding a Failsafe to Songs-reading so it will not accidentially read over current Array-boundaries INSTALL.TXT, README.TXT: Updated docs and hopefully made them more user-friendly 20100221 -------- main/kconfig.c, main/kconfig.h, main/menu.c, main/playsave.c, main/playsave.h, main/text.h: Overhaul for CONTROLS menu; Cleaned kconfig-code a little and slacked out keymap arrays 20100219 -------- main/gauges.c, main/text.c, main/weapon.c: The little light bulb showing homing warning in Cockpit was broken and I replaced it; Rewritten code to show weapon text in Cockpit and Statusbar slightly; Instead of using hardcoded weapon strings, use from descent.txb and fixed too long spreadfire string properly main/text.c: Small fix for most recent commit: Removed an obsolete d_free main/songs.c, main/songs.h: Making reading of descent.sng a bit more flexible; Not dynamically allocated, yet, since missions are not as well 20100214 -------- d1x.ini, arch/include/joy.h, arch/sdl/joy.c, main/endlevel.c, main/inferno.c, main/kconfig.c, main/slew.c, misc/args.c: Cleaning up Joystick code and on the way supporting more axes and buttons; Also fixed bug with channel_mask byte causing trouble using some axes ingame; Added argument to set environment variable which disables sticky keys (for SDL >= 1.2.14) 20100208 -------- main/menu.c, main/scores.c, main/scores.h: Move all globals in scores.c into struct members/local variables main/game.c, main/newdemo.c: Don't make another Game_wind when advancing a level, fixing failed asserts / slow turning arch/sdl/window.c: Don't send an EVENT_WINDOW_DEACTIVATED when closing a window if it wasn't the front window, now the game works properly after you're shown on the high scores main/collide.c, main/object.c, main/object.h, main/state.c: Introduced hitobj_list for persistent weapon objects to keep track of multiple objects the weapon is in contect with to prevent it from doing FPS-based damage; Made persistent weapon objects not die on debris but just decrease their shields like when an ordinary player/robot is hit - makes more sense main/console.c: Write gamelog.txt buffered so it will not stress the medium it's saved on 20100207 -------- main/game.c, main/gameseq.c, main/inferno.c, main/inferno.h, main/menu.c, main/newdemo.c: Create the main event loop and use it for the game and main menu main/scores.c: Make the scores menu into a window d1x-rebirth.xcodeproj/project.pbxproj, include/3d.h, main/aistruct.h, main/game.h, main/gamefont.h, main/gameseq.h, main/inferno.h, main/laser.h, main/polyobj.h, main/robot.h: Move MAX_SUBMODELS from inferno.h to polyobj.h, fixing #include loop by removing some (mainly object.h) and instead using explicit 'struct' declarations; compile net_ipx.c for Mac SDL Video build main/gameseq.c, main/gameseq.h, main/menu.c, main/menu.h: Split select_filename into [existing] RegisterPlayer and select_demo for better clarity 20100206 -------- main/newmenu.c: Set the correct scroll position for the listbox when it's shown main/gameseq.c, main/gameseq.h, main/menu.c, main/menu.h: Handle player selection and demo playing in filename_menu_handler, fixing bug where it won't leave the player listbox if there's no LastPlayer; close do_options dialog when changing resolution 20100205 -------- main/game.c, main/gameseq.c, main/newdemo.c: Use palette_save and palette_restore for all windows displayed over Game_wind, not just for do_option main/gameseq.c, main/newmenu.c: No showing the main menu background between loading a level and playing it (syncing with D2X) main/window.c: Send EVENT_WINDOW_DEACTIVATE before EVENT_WINDOW_ACTIVATE, ensuring cursor remains shown when appropriate main/physics.c: In do_physics_sim() only set velocity from movement for certain objects which actually do collisions like Player or Robots - otherwise we might be able to shoot down projectiles or produce other unfortunate glitches 20100202 -------- arch/include/event.h, arch/sdl/window.c, main/automap.c, main/dumpmine.c, main/game.c, main/gamecntl.c, main/gamesave.c, main/gameseq.c, main/kconfig.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c: Add EVENT_WINDOW_DEACTIVATED; move many game_flush_inputs, start_time and stop_time calls to game_handler as well as digi_pause_digi_sounds and digi_resume_digi_sounds main/inferno.c: Hide all other windows before showing error dialog, hopefully so errors don't happen while the error dialog is there arch/include/event.h, arch/sdl/window.c, main/game.c, main/inferno.c, main/newmenu.c: Put LeaveGame longjmp back, but in response to new EVENT_WINDOW_CLOSED, fixing demo issues; fix compiler error in last commit 20100201 -------- arch/carbon/conf.h, d1x-rebirth.xcodeproj/project.pbxproj, main/kconfig.c, main/menu.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/newmenu.h: Leave kconfig_idle early if exiting kconfig to avoid erroneous memory access; initialise menu's citem properly; add EVENT_NEWMENU_CHANGED; activate USE_IPX in Xcode while I'm still changing net_ipx.c 20100131 -------- main/newmenu.c: Fix memory errors, but still dynamically allocate menu and lb so it doesn't have to stay in newmenu_do4 and newmenu_listbox1 respectively main/automap.c, main/game.c, main/game.h, main/multi.c, main/multi.h, main/net_ipx.c, main/net_udp.c, main/newmenu.c: Fix crashing when doing menus in multiplayer, don't let player move when in automap main/automap.c, main/kconfig.c, main/newmenu.c: Adding a bunch of memset's to menu/automap creations so we won't run into uninitialized variables 20100130 -------- arch/sdl/event.c, arch/sdl/key.c, main/menu.c, main/newmenu.c, main/newmenu.h, main/state.c: Send EVENT_KEY_COMMAND from key.c; add EVENT_NEWMENU_DRAW for state restore; place newmenu and listbox calls to callback so they can override ALL newmenu behaviour main/newdemo.c: Fix warning in newdemo_stop_recording where it should set the last char of filename to 0, not the next variable main/menu.c, main/newmenu.c: Fixed two memory errors inside menu GUI 20100129 -------- main/automap.c, main/automap.h, main/game.c, main/gamecntl.c, main/kconfig.c, main/multi.c, main/multi.h, main/net_ipx.c, main/net_udp.c, main/newmenu.c: For multiplayer, close menus from game_handler by doing frame processing in response to EVENT_WINDOW_DRAW, replacing multi_menu_poll system with single multi_menu_check call main/newmenu.c: Initialise lb->first_item to 0, not -1, preventing crash if you make a listbox selection very quickly d1x.ini, arch/ogl/gr.c, arch/sdl/gr.c, include/args.h, main/inferno.c, main/newmenu.c, misc/args.c: Added real Doublebuffering to SDL-build; While on the way, making Bpp selection available for SDL-build, too 20100128 -------- main/playsave.c, main/playsave.h, main/object.c, main/render.c, main/hud.c, main/hostage.c, main/newdemo.c, main/gamerend.c, main/endlevel.c, main/game.c, main/gauges.c: Made PlayerCfg.CockpitMode an array to hold two values: 0 to store the actual "cockpit", 1 to also store Letterbox, Rear, etc. Greatly helps to switch and restore views - especially in Demo playback which now properly selects modes main/newdemo.c: Added a new code to properly re-record view/cockpit-events at beginning and end of Demo recording so views will be fine if switched before recording started; Also added lost sequence to record Rear-view reset between levels; Last but not least, record wall tmaps so opened/blasted doors will be shown correctly if opened/blasted before recording; Everything done without breaking the Demo format! arch/sdl/window.c, main/automap.c, main/game.c, main/gamecntl.c, main/kconfig.c, main/menu.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c: Make response to EVENT_WINDOW_CLOSE conform to 'handling' system - returning 1 means abort closing main/kconfig.c, main/newmenu.c: Tidy up newmenu_show/hide_cursor calls main/newmenu.c: Allow user to abort close, for whatever reason (helps with my next commit) main/gamesave.c, main/newdemo.c, main/object.c, main/object.h, main/state.c: Improved Object signature assignment and made sure there will be no duplicates; Also used short-ranged values only so Demo system won't screw up main/menu.c: When deleting a player also delete the Multiplayer efficiency file 20100127 -------- main/game.c, main/game.h, main/gamecntl.c, main/gameseq.c, main/kmatrix.c, main/multi.c, main/net_ipx.c, main/net_udp.c, main/newdemo.c, main/render.c: Remove all uses of LeaveGame jmpbuf to allow more changing of main loop main/gameseq.c, main/inferno.c, main/menu.c, main/newmenu.c: Allow escape from player listbox if appropriate; call RegisterPlayer only from main menu for more flexibility; actually use file_list block so deleting players/demos doesn't crash it 20100126 -------- main/newdemo.c: Once again improving Demo Interpolation code, regarding changes from rev993, reducing Viewport flicker and jitter 20100124 -------- main/gauges.c: Rewrote code for showing Cloak-effect on Cockpit and Statusbar, because it became bugged with changed order of function calls do_cloaked_stuff() and render_gauges() 20100123 -------- main/gamecntl.c, main/inferno.c, main/menu.c: Move the editor call out of the Function_mode loop, for later overhaul 20100121 -------- main/newdemo.c: Removed the new Demo Interpolating code and added the improvements to the old one 20100120 -------- arch/include/event.h, arch/sdl/event.c, arch/sdl/window.c, main/automap.c, main/game.c, main/gamecntl.c, main/kconfig.c, main/menu.c, main/net_ipx.c, main/net_udp.c, main/newmenu.c, main/state.c: Add EVENT_WINDOW_ACTIVATED, change EVENT_DRAW to EVENT_WINDOW_DRAW and EVENT_CLOSE to EVENT_WINDOW_CLOSE main/automap.c, main/game.c, main/gamecntl.c, main/kconfig.c, main/newmenu.c: Fix major issues with last commit - tidy up window callbacks to dodge EVENT_WINDOW_ACTIVATED where it's unnecessary or erroneous to respond to 20100119 -------- main/net_ipx.c, main/net_udp.c: Make net_ipx_show_game_rules and net_udp_show_game_rules into windows 20100118 -------- main/kconfig.c: Make kconfig menus into windows - allowing drawing of the game screen behind, changing of item to change while question mark flashing and clicking out of item change 20100117 -------- main/menu.c: Respond to EVENT_NEWMENU_SELECTED for options_menuset and input_menuset, so the input menu will have THE event loop for kconfig 20100115 -------- main/menu.c: For get_filename, put mode and find variables in a structure - fixing 64-bit problem and allowing freeing of PHYSFS file list in callback in future, respectively 20100109 -------- arch/include/window.h, main/game.c, main/gamecntl.c, main/gamerend.c: Make pause box a window 20100108 -------- arch/sdl/event.h, main/menu.c, main/newmenu.c, main/newmenu.h: Add EVENT_NEWMENU_SELECTED, allowing a newmenu/listbox selection to be handled in the callback. Demonstrate with "Select Song" menu 20100107 -------- main/gamecntl.c, main/newdemo.c: New Interpolation method for demos and a small hack to fix this Interpolation if duplicate object signatures appear (mostly) arch/carbon/conf.h, arch/include/event.h, arch/include/key.h, arch/sdl/event.c, main/escort.c, main/game.c, main/gamecntl.c, main/gamesave.c, main/gameseq.c, main/kmatrix.c, main/menu.c, main/mission.c, main/multi.c, main/multi.h, main/net_ipx.c, main/net_ipx.h, main/net_udp.c, main/net_udp.h, main/newdemo.c, main/newmenu.c, main/newmenu.h, main/scores.c, main/state.c, main/weapon.c: Change newmenu and listbox callback systems, adding use of d_event, for greater flexibility 20091227 -------- main/newmenu.c: Make listboxes into windows main/automap.c, main/automap.h: Put most of the remaining globals in automap.c in the 'automap' struct 20091226 -------- arch/include/key.h, arch/sdl/event.c, arch/sdl/key.c, main/automap.c, main/game.c, main/gamerend.c, main/kconfig.c, main/newmenu.c: Make newmenus into windows, allowing redrawing of automap and game to take place outside of newmenu.c; remove redundant keyd_repeat 20091213 -------- main/game.c: Make sure the Game_wind only gets freed once when escaping demo playback 20091212 -------- main/game.c: Make sure the Game_wind always gets freed when exiting the game screen, fixing flashing automap and framerate reduction after playing demos 20091211 -------- arch/linux/ukali.c: Fixing possible string overflow while using KALI_PROCESS_NAME 20091208 -------- d1x-rebirth.xcodeproj/project.pbxproj, main/gameseq.c, main/menu.c, main/menu.h, main/newdemo.c, main/newmenu.c, main/newmenu.h: Move newmenu_get_filename to menu.c, call it get_filename and have it use newmenu_listbox1; support long demo filenames 20091205 -------- main/newmenu.c: Make newmenu.c nearly identical between D1X and D2X 20091202 -------- arch/include/event.h, arch/include/window.h, arch/sdl/window.c, d1x-rebirth.xcodeproj/project.pbxproj, main/automap.c, main/game.c, main/game.h, main/gamecntl.c, main/kconfig.c, main/kconfig.h: Make the automap into a 'window', make kconfig.c more similar between D1X and D2X 20091201 -------- main/gauges.c: Squishing string-related bugs in Bomb display and Weapon reordering 2d/clip.h, 2d/line.c: Renaming FSCALE to FIXSCALE preventing possible naming conflicts 20091130 -------- d1x-rebirth/arch/carbon/conf.h, d1x-rebirth.xcodeproj/project.pbxproj: Update to not compile redundant net_ipx.c for Mac OS X main/newdemo.c, main/newdemo.h, main/gamerend.c, main/game.c, main/gauges.c, main/gamecntl.c: Reintroduced Newdemo_game_mode to prevent demo playback from entering code parts it should not and fixing a bug with Multiplayer demos along the way, introduced in rev. 953 arch/ogl.c, main/endlevel.c: Draw Endlevel sequence with correct DepthFunc include/u_mem.h, main/newmenu.c, 2d/2dsline.c, 2d/bitblt.c, 2d/pixel.c, 2d/rle.c, 2d/line.c, 2d/gpixel.c, SConstruct: Making files in 2d directory more similar and removed unused and broken code; Fixing a bunch of memory errors; Removed stack protecting flag for gcc in debug mode 2d/clip.h: Fixed missing define introduced in the last revision 20091129 -------- d1x-Info.plist, d1x-rebirth.xcodeproj/project.pbxproj, d1xgl-Info.plist, English.lproj/InfoPlist.strings: Make Mac version numbers consistent, Xcode build settings tidy up main/collide.c, main/multi.c, main/multi.h, main/menu.c, main/powerup.c, SConstruct, arch/linux/ipx.c, arch/carbon/conf.h: Adding macros USE_UDP and USE_IPX for the compiler to compile with either UDP- and/or IPX-support and removed the older IPX macros 20091128 -------- main/net_udp.c, main/menu.c, d1x-rebirth.xcodeproj, D1X.make, arch/carbon/conf.h: Fixed building error on Windows caused by false socket variable; Fixed compiler Warnings on Mac; Updated Mac build files; Unification in version numbering 20091127 -------- main/fireball.c, main/gameseq.c, main/menu.c: Fix some compile errors, including for the non-NETWORK build 20091124 -------- include/args.h, main/net_udp.c, main/net_udp.h, main/gameseg.c, main/fireball.c, main/multi.c, main/multi.h, main/inferno.c, main/menu.c, main/titles.c, main/object.c, main/kmatrix.c, main/kmatrix.h, main/newdemo.c, main/config.c, main/net_ipx.c, main/config.h, main/net_ipx.h, main/gameseq.c, main/gamerend.c, main/vers_id.h, main/gauges.c, main/gamecntl.c, INSTALL.txt, misc/args.c, SConstruct, d1x.ini, README.txt, arch/linux/ipx.c, arch/linux/ipx_kali.c, arch/win32/ipx.c: Abstracting networking protocols - Step 4: Implemented new UDP layer with Client/Server communication, Packet Loss Prevention and strict Version checking. Netgames list will follow later. main/net_udp.c: Remove the IP check when processing game info or version deny as the IP might be translated (IPv6 especially) main/net_udp.c, main/net_ipx.c, SConstruct: Improved Disconnect-handling between levels; Improved Kick-handling; Do not say that IPv4 and IPv6 builds are not compatible in scons -h anymore include/timer.h, main/net_udp.c, main/newmenu.c, main/multibot.c, main/menu.c, main/titles.c, main/kmatrix.c, main/net_ipx.c, main/gameseq.c, main/digiobj.c, arch/sdl/timer.c: Removed timer_get_approx_seconds() and replaced with timer_get_fixed seconds since it was too inaccurate and created significant offset main/net_udp.c: Again making the joining safer 20091122 -------- main/piggy.h: Adding cfile.h include to get CFILE definition work again 20091117 -------- 3d/interp.c, arch/ogl/gr.c, arch/sdl/gr.c, include/gr.h, main/kconfig.c, main/menu.c: Only list resolutions that can actually be used, using new gr_check_mode 20091115 -------- main/gamecntl.c, main/newdemo.c, main/newdemo.h, main/newmenu.c, main/text.c: Add endian converter for demos, read shareware demos, various bugfixes to demo system 20091005 -------- d1x-rebirth.xcodeproj/project.pbxproj, include/physfsx.h, main/ai.c, main/ai.h, main/cntrlcen.c, main/cntrlcen.h, main/fuelcen.c, main/fuelcen.h, main/object.c, main/object.h, main/player.c, main/player.h, main/state.c, main/switch.c, main/switch.h, main/wall.c, main/wall.h, SConstruct: Read big endian savegames on little endian computers and vice versa 20090911 -------- main/ai.c, main/ai.h, main/state.c: Fix compile error with ai_restore_state and include necessary ogl_init.h in state.c (whoops) 20090909 -------- d1x-rebirth.xcodeproj/project.pbxproj, utilities/extractD1Data.cpp, utilities/SConstruct: Add program for extracting Mac data files from installer 20090822 -------- main/ai.h, main/state.c: Make state.c more similar between D1X and D2X 20090810 -------- arch/sdl/window.c, main/automap.c, main/game.c, main/inferno.c, main/multi.c: Make the game screen into a 'window', handling events through event_process 20090701 -------- main/cntrlcen.c, main/collide.c, main/effects.c, main/fireball.c, main/fuelcen.c, main/fuelcen.h, main/game.c, main/game.h, main/gamecntl.c, main/gamerend.c, main/gameseq.c, main/multi.c, main/net_ipx.c, main/newdemo.c, main/render.c, main/songs.c, main/state.c, main/switch.c: Make game.c more similar between D1X and D2X, making related changes to other files (!) 20090607 -------- d1x-rebirth.xcodeproj/project.pbxproj, main/game.c, main/game.h, main/gamecntl.c, main/gamerend.c, SConstruct: Split game.c into game.c, gamecntl.c and gamerend.c like d2x 20090531 -------- include/u_mem.h, main/inferno.c, main/menu.c, main/titles.c: Make inferno.c more similar between D1X and D2X, better handling of ordering/commercial software screen 20090522 -------- arch/sdl/window.c: Add include directives for last commit (whoops) 20090521 -------- arch/include/event.h, arch/include/window.h, arch/sdl/event.c, arch/sdl/mouse.c, arch/sdl/window.c, d1x-rebirth.xcodeproj/project.pbxproj, main/inferno.c, SConstruct: Add new window system, not used yet 20090506 -------- main/config.c, main/config.h, main/menu.c, main/songs.c: Add option to force either Redbook or Jukebox to use the playing order for the game CD 20090503 -------- main/config.c, main/config.h, main/menu.c: Make some files more similar between D1X and D2X 20090430 -------- arch/carbon/conf.h, d1x-rebirth.xcodeproj/project.pbxproj, main/gauges.h, main/multi.h: Disable network support for Mac OS X for now arch/carbon/SDL_main.c, arch/ogl/ogl.c, arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, arch/sdl/digi.c, arch/sdl/event.c, arch/sdl/gr.c, arch/sdl/joy.c, arch/sdl/key.c, arch/sdl/mouse.c, arch/sdl/rbaudio.c, arch/sdl/timer.c, include/physfsx.h, main/automap.c, main/console.c, main/digiobj.c, main/lighting.c, main/mission.c, misc/error.c: Remove redundant conf.h directives 20090409 -------- main/multi.c, main/multi.h, main/multibot.c, main/menu.c, main/kmatrix.c, main/net_ipx.c, main/net_ipx.h, main/gameseq.c, main/fuelcen.c, main/ai.c, main/game.c: Abstracting networking protocols - Step 3: Renaming network_* functions to net_ipx_*, writing wrappers for protocol dependend functions in multi.c, Implementing protocol selection and Cleanup - Next up: Implementing new UDP layer 20090320 -------- include/ipxdrv.h, main/ipxdrv.c, main/newmenu.c, main/fireball.c, main/multi.c, main/multi.h, main/menu.c, main/state.c, main/newdemo.c, main/net_ipx.c, main/net_ipx.h, main/gameseq.c, main/endlevel.c, main/game.c, main/gamecntl.c, SConstruct, arch/linux/ipx.c, arch/linux/ipx_kali.c, arch/win32/ipx.c: Abstracting networking protocols - Step 2: Introducing new structure to hold protocol-dependend and -independend information about Netgame and it's Players; Further isolation of the IPX code and renaming the netdrv_* code to ipxdrv_* as this is now actually IPX-only; Next up: Renaming network_* functions to net_ipx_*, writing wrappers for protocol dependend functions in multi.c, Implementing protocol selection and Cleanup 20090304 -------- various: Abstracting networking protocols - Step 1: Renaming network-related files; Removing net_ipx.h (former network.h) includes from as much files as possible to make isolation of IPX-related functions easier in Step 2; Version defines Cleanup - needed later for good Version-Checking 20090303 -------- arch/include/digi_mixer_music.h, arch/include/jukebox.h, arch/sdl/digi_mixer_music.c, arch/sdl/digi_mixer.c, arch/sdl/digi.c, arch/sdl/init.c, arch/sdl/jukebox.c, arch/sdl/rbaudio.c, include/rbaudio.h, main/automap.c, main/config.h, main/credits.c, main/digi.h, main/game.c, main/kconfig.c, main/kmatrix.c, main/menu.c, main/network.c, main/newmenu.c, main/scores.c, main/songs.c, main/songs.h: Associate the jukebox with Redbook Audio via new 'extmusic' layer - separating from MIDI and making it handle ALL music (not just game music) 20090223 -------- main/game.c, main/gauges.c, main/menu.c: Made our Cockpit-Transparency decoding function a bit safer for current and possibly new code flow main/gauges.c: Small positional correction for homing-warning bitmap 20090222 -------- main/fireball.c: Fixed param handling of expl_obj in do_explosion_sequence for the case that free_object_slots might have it set to OF_SHOULD_BE_DEAD before it's actually attached to another object d1x-rebirth.xpm, d1x-rebirth.desktop: Added desktop UI files... 20090217 -------- main/object.c, main/object.h: Made Max_used_objects an absolute defined value; Made num_objects globally available 20090215 -------- main/network.c, main/noloss.c, main/noloss.h: Added list to keep trace of received PDATA packets so receiver won't interpret them several times 20090209 -------- main/kconfig.c: Removed PH_SCALE on Keyboard readings as caps movement not in sync to FrameTime; Removed scaled Joystick reading as it's not necessary anymore main/gameseq.c: When creating new player, make sure string is long enough for use with players dir 20090208 -------- main/multi.c: Fixed connect-state mess in order of kmatrix flow main/menu.c: Make sure HostAddr buffer is directly saved as soon as we confirm it in the entry field 20090206 -------- INSTALL.txt, main/network.c, main/network.h, main/noloss.c: Small docs update; Noloss thinking flaw correccted: Add a special type for PDATA packets that need to be ACK'd so other clients won't ACK everything 20090203 -------- main/network.c, main/noloss.c: Close out fire from queue list as this is not necessarily needed to keep games in sync; While processing the noloss queue, only process 5 packets max 20090202 -------- main/newdemo.c: Defined some default cockpit modes in Demo mode so we do not get invalid values when demo starts in non-default-view mode (as new HUD modes are only triggered at beginning and end of event) main/game.c: Made FPS string statically right-justified - unrelated to actual FPS string width preventing jumps main/multi.c, main/multi.c: Removed MULIT_POS_* hanldings as these signals are not created anymore 20090201 -------- main/netdrv_udp.c: Fixing bug with incorrect/missing UDP port termination main/network.c, main/network.h, main/multi.h, main/netdrv_udp.c, main/netdrv_udp.h, main/noloss.c, main/noloss.h, SConstruct: Added Packet-loss prevention code for Netgames 20090131 -------- main/songs.c: Last track is endgame track for any audio CD, endgame track not played when a level is started, jukebox/redbook works in game even if no MIDI songs 20090130 -------- arch/ogl/ogl.c, main/render.c: New level render order for better seperation and blending between transculent level geometry and sprites 20090129 -------- main/netdrv_udp.c: Decreasing delay from timer_delay2 to timer_delay for sending/receiving packets when connecting to UDP host due to FPS-dependent inconsistencies in timer_delay2 causing packets possibly not received or sent frequently 20090126 -------- include/netdrv.h, main/network.c, main/menu.c, main/netdrv_udp.c, main/netdrv_udp.h, main/netpkt.c, main/netpkt.h, main/netdrv.c, arch/linux/netdrv_ipx.c, arch/linux/netdrv_kali.c, arch/win32/netdrv_ipx.c: Changed function naming convention in netdrv and below to general Descent code convention arch/carbon/conf.h, d1x-Info.plist, d1xgl-Info.plist, English.lproj/InfoPlist.strings: Update version to 0.55.1 20090124 -------- main/game.c: Removed some old code to smooth FrameTime we don't need anymore 20090122 -------- main/newdemo.c: New condition to switch to Interpolated demo playback - the old one did NOT make ANY sense at all 20090117 -------- arch/sdl/mouse.c, main/menu.c, main/playsave.c, main/playsave.h: Made MouseFilter selectable over Controls menu while defaulting to OFF - Saved in PLX d1x.ini, include/args.h, main/inferno.c, main/laser.c, misc/args.c: Took out old missile tracking code to be selectable over command-line to preserve consistency 20090116 -------- arch/ogl/ogl.c, main/gamefont.c, main/menu.c: Reduced size of vectorial reticle to match the size of the original one; Only scale fonts by float if Texture filtering is on - otherwise scale by int arch/ogl/gr.c: Error handling while dumping TGA file - (partially) Patch by v66r 20090115 -------- main/inferno.h, main/netdrv_udp.c, main/netdrv.c, main/game.c: Cleaning up the mess from revision 892... arch/sdl/mouse.c, main/automap.c, main/game.c, main/game.h, main/gameseq.c, main/kconfig.c: Fixed typo in mouse delta reading cleaning not up Z-Axis; Giving automap a nicer Frameloop; Small cleanup 20090114 -------- main/network.c, main/multi.c, main/inferno.h, main/netdrv_udp.c, main/netdrv_udp.h, main/config.c, main/netdrv.c, main/game.c, arch/ogl/ogl.c, arch/ogl/gr.c, arch/sdl/digi_mixer_music.c, include/ogl_init.h, include/cfile.h, misc/args.c: Patch from Damjan Cvetko for better support building with a non-free compiler... 20090113 -------- main/collide.c, main/physics.c: Adjusted D1 Lifter collision damage according to D2 to scale with FPS as Melee combats can happen in every frame; Actually set velocity from movement when colliding with objects arch/sdl/jukebox.c: Use a 2D array to allow playing of songs by track number in future main/collide.c: Added some randomness to collision sound delays and synced robot-player collision sprites to same steps 20081230 -------- SConstruct: prefix is now an argument (useful for auto-builds) debian/*: created the debian packaging files 20081227 -------- arch/carbon/conf.h, d1x-Info.plist, d1x-rebirth.xcodeproj/project.pbxproj, d1xgl-Info.plist, English.lproj/InfoPlist.strings: Increment Mac version number, update project for latest Xcode 20081226 -------- main/netdrv_udp.c: Fixed segfault via buffer overflow when attempting to start or join a UDP/IP netgame. 20081224 -------- main/inferno.h: Now the Mac command keys work (whoops) 20081223 -------- main/config.c: Make Redbook the default for Mac, because MIDI is buggy 20081221 -------- 2d/pcx.c, d1x-rebirth.xcodeproj/project.pbxproj, D1X.make, main/config.c: Fix Mac OS 9 compile issues, update Xcode project arch/carbon/conf.h: Set SHAREPATH to "." for Mac OS X so reading data from DXX's directory ACTUALLY WORKS 20081220 -------- SConstruct, main/menu.c: Removed (#if 0) the unfinished Tracker stuff for our Release so it won't confuse the Win32 build 20081213 -------- main/network.c: Fix short_frameinfo sending code for big endian processors main/game.c, main/game.h, main/menu.c: Seperated help screens for game, netgame and demo; Also show them in Controls menu; Small Menu UI fix for ScrollOffset when calling menus in a scrolled area of a menu 20081212 -------- main/netpkt.c, main/netpkt.h, main/network.c, main/network.h: Cleaned a frameinfo-packet related code and introduced more of D2X - especially for short packets (which is thankfully covered by Version checking) main/multi.c: Added /KillReactor command to blow up the reactor in Multiplayer games 20081207 -------- arch/include/key.h, arch/sdl/key.c, d1x-rebirth.xcodeproj/project.pbxproj, main/game.c, main/inferno.c, main/inferno.h, main/kconfig.c, main/newdemo.c, main/newmenu.c, main/piggy.c: Get Mac command keys working, update Xcode project 20081201 -------- main/kconfig.c: Restored vertical_thrust_time behaviour combined with slide_on to be inverted - respecting user's wishes 20081126 -------- arch/ogl/ogl.c: Deactivated depth writing fo g3_draw_bitmap() sprites to prevent rendering errors when clipped in some cases 20081122 -------- main/fvi.c, main/pysics.c: Took out the "disable_new_fvi"-hack. After all we do not need that specific optimisation anymore and also without it we can have more accurate collisions with non-player objects. After playtesting for a while let's just do this. 20081121 -------- main/game.c: Do not allow to restore games while player is dead... again - to much trouble right now main/render.c: Increasing Render_depth to max. if OGL build (we probably should get rid of these variables, but may still be handy for non-3D-accellerated build optimisations) 20081120 -------- main/ai.c: When we reached MAX_BOSS_TELEPORT_SEGS in init_boss_segments, make sure we also escape out of the for-loop - otherwise we still might overflow main/ai.c, main/object.c: Some timer-Failsafe in robot/boss dying frames; Fixed logical flaw in create_small_fireball_on_object() closing out sound effects on robots 20081119 -------- main/game.c: Actually demand ANY valid key to abort the Death sequence main/songs.c: Do a songs_init() each time a song is played and try to read a new descent.sng - supporting descent.sng files in hog archives 20081118 -------- main/console.c: When printing Gamelog, make sure canvas is NULL main/newmenu.c, main/multi.c, main/game.c, ui/inputbox.c, ui/menubar.c, arch/sdl/event.c, arch/sdl/key.c, arch/include/key.h: Yet another UNICODE overhaul - Using seperate buffer for UNICODE chars and only use it in key_ascii() while still using keysyms for the rest of the program so we do not screw up readings by key values altered by modifers - possibly still room to optimize main/game.c: Fixed cheats! main/automap.c: Changed keys for Automap Viewing Distance to F9/F10 - Minus/Equal is not Layout independent 20081115 -------- arch/sdl/digi_audio.c: include/error.h, main/console.c, main/inferno.c: Added other SDL_(Un)LockAudio statements to protect the audio_mixcallback function - making that hopefully stable on multicores; Resetting warn_func at quit_request so we do not accidently show any menu; Open gamelog.txt unbuffered 20081114 -------- include/args.h, include/3d.h, include/rle.h, include/rbaudio.h, main/text.c, main/text.h, main/bm.c, main/gamefont.c, main/inferno.c, main/bm.c, main/bmread.c, main/piggy.c, main/render.c, main/render.h, main/songs.c, main/gameseq.c, main/gamerend.c, main/netdrv.c, main/endlevel.c, main/endlevel.h, main/terrain.c, main/terrain.h, main/polyobj.c, main/polyobj.h, main/game.c, main/gauges.c, main/texmerge.c, main/mission.c, main/mission.h, misc/args.c, 2d/rle.c, 3d/setup.c, SConstruct, D1X.make, arch/linux/alsadigi.c, arch/ogl/gr.c, arch/sdl/digi_mixer.c, arch/sdl/joy.c, arch/sdl/init.c, arch/sdl/rbaudio.c, arch/sdl/gr.c, arch/sdl/key.c, arch/sdl/digi_audio.c, arch/include/mouse.h: Using a clean flow for closing game data at the end of main() instead of using atexit; Now only use atexit for SDL stuff, error, mem, console (and editor which we do later); Small Cleanup 20081110 -------- main/credits.c, main/inferno.c, main/menu.c, main/newmenu.c: Small Cleanup: Using timer_delay for credits timer as timer_delay2 would respect VSync and change speed of the Credits scrolling; Cleaned that Start/Join Netgame cases up a bit; Removed the excessive use of atexit in newmenu... more to come misc/error.c: When Error() is called, set Function_mode to FMODE_EXIT... basically to prevent the messagebox would try to render the game in background if the Error would happen while mission loading 20081109 -------- include/args.h, main/inferno.c, main/gamefont.c, main/menu.c, main/game.c, main/gauges.c, main/gauges.h, misc/args.c, d1x.ini, arch/ogl/ogl.c, arch/ogl/gr.c: Always keep aspect scaling (lowest scalar of width and height) for fonts, lines, dots, spheres, reticle and non-Cockpit-/Statusbar-related HUD-elements; Moved the Cockpit alpha decoding to gauges.c and created a seperate bitmap for the alpha fields and create subbitmaps from this one - more memory but this way we do not modify the cockpit bitmap itself 20081107 -------- arch/sdl/key.c: Only read UNICODE values from 31 to 254 to make sure we do not read any non-printable characters and prefer the keysym that way; Added left and right Command Key for MAC Keyboards 20081103 -------- misc/args.c: Fixed Typo main/ai.c, main/collide.c: Made move_towards_segment_center() use move_towards_vector() instead of just changing object position suddenly - smoother; Changed back the robot:controlcen collision back to original - the AI just relies to often on no-damage collisions, especially when our segment suddenly is a controlcen 20081101 -------- main/config.c, main/menu.c, main/newmenu.c, main/piggy.c: Fixed possible overflows in Jukebox Path; Menu GUI improvements: Correct inputbox scaling for font widths, a little performance boost when determinating string-part to show in inputbox, make it possible to flip over from first/last menu entry to last/first even if it's a ScrollBox, Scrolling via Maousebutton now works with delay; Made reading for Piggy data always break up in loops when reached end of file instead of provoking possible error if *data-count < max-data-count* arch/sdl/key.c: Make sure that if we use UNICODE, we always take non-control type chars and - as we only want lowercase letters - convert chars if shift is pressed arch/ogl/ogl.c. main/game.c: I always forget glLineWidth takes previous setting if arg is <1; Made the decodebuffer for cockpit static as the bitmap data pointer points to it 20081031 -------- arch/include/key.h, arch/sdl/key.c, main/game.c, main/kmatrix.c, main/multi.c, main/multi.h, main/newmenu.c, main/scores.c, ui/inputbox.c, main/menubar.c: Always use printable UNICODE characters for the key_handler and included routine to assign key symbols to UNICODE so we get an equivalent of a Key-Released state which we need for the Keyboard buffer; Removed the shifted_ascii_value field from key_props and stored all usable characters in seperate rows; Improves Text input and makes keyboard mapping independent from keyboard layout without breaking any compability arch/ogl/ogl.c: Make glLinewidth depend on screen height, not width (for Widescreen monitors) (commit came with last revision, sorry) 20081030 -------- INSTALL.txt, README.txt: Docs update: Infos about Jukebox over SDL_mixer, SDL_mixer is not experimental anymore, yet another .de->.com change d1x.ini, main/inferno.c: Show debug help screen options in release build as well as some might be actually useful for players main/menu.c: Add a messagebox informing to restart the game if either VSync or 4x Multisampling has been (de)selected 20081029 -------- 2d/font.c, main/gamefont.c, main/gamefont.h, main/menu.c: Scale fonts by float values and filter them if texture filtering is on; Another fix for the code flow in change_res() as the check for minimal custom resolution always failed main/collide.c: Yet another check for collide sounds as FixedStep is not necessarily true if the actual collision happens main/newmenu.c: Cast LINE_SPACING to integer for menu Scrollbox usages - fixing scrolling issues with non-integer-scaled font sizes 20081028 -------- arch/ogl.c, include/gr.h, main/game.c, main/gauges.c, main/gauges.h, main/newmenu.c: Removed hack for Cockpit-window transparencies and added function to decode and add alpha to the bitmap directly (now works in non-OGL as well); Using sub-bitmaps for Cockpit-windows and menu backgrounds; Cleaned old bkg stuff from menu GUI main/game.c, main/manu.c, main/newmenu.c: Fixes for my last revisions: More reliable check for cockpit_decode_alpha, more reliable check is newmenu sub-bitmap needs to be re-created, call gr_set_mode() in change_res() with correct Game_screen_mode INSTALL.txt, README.txt: Docs update: We moved from www.dxx-rebirth.de to www.dxx-rebirth.com! arch/sdl/gr.c, arch/ogl/gr.c, arch/ogl/ogl.c, include/args.h, main/game.c, main/inferno.c, main/menu.c, main/playsave.c, main/playsave.h, misc/args.c: Cleanup: Renderstats; Made PRShot a non-OpenGL-related feature and added to Misc Options; Added command for SDL_ASYNCBLIT to command-line args 20081023 -------- main/multi.c, main/network.c: Fixed handling for multi_quit_game; Always keep setting -1 for ping table entry of current player so just not to use any previous entry 20081022 -------- main/menu.c, main/netdrv_udp.c, main/netdrv_udp.h: Removing reset of Game_screen_mode while change_res Fullscreen toggle (wtf is the point?); Adding a third valid state for UDP peers so we can get more order in handshaking process - should fix problem when two clients join (and shake) simultaniously 20081021 -------- iff/iff.c, main/inferno.c: Fix some gcc 4.0 warnings (-wall flag) 20081020 -------- main/menu.c: resolution 1440x960 to 1440x900 - typo d1x.ini, include/args.h, main/inferno.c, main/menu.c, main/netdrv_udp.c, main/network.c, misc/args.c: Readded -ip_hostaddr optional to the value stored in descent.cfg for automated program starts or whatever; Fix by Locate: Correctly close UDP sockets on Win32; Fix by Locate: Ability to select Secret levels on Multiplayer in D1X again which was broken in r619 20081019 -------- arch/sdl/gr.c, arch/ogl/gr.c, include/gr.h, main/game.c, main/menu.c, main/newmenu.c: Setting Fullscreen toggle setting the GameCfg value at each change, not only in change_res(); Do not allow the toggle while playing since ALT-GR+ENTER could be used as game-keys; Reorganized Resolutions menu to automatically calculate aspect ratio for preset resolutions and making custom fields exclusive 20081016 -------- main/credits.h, main/newmenu.c, main/newmenu.h, main/menu.c, main/playsave.c, main/playsave.h, main/titles.c, main/lighting.c, main/lighting.h, main/wall.c, main/render.c, main/newdemo.c, main/newdemo.h, main/gameseq.c, main/scores.c, main/endlevel.c, main/laser.c, main/game.c, main/kconfig.c, main/kconfig.h, main/credits.c, arch/sdl/mouse.c, arch/include/joy.h: Giving credits function ability to use custom creditfile (again); Made laser-offset for laser exclusive so Prox mines won't go tru doors; Preventing cycling tru cockpit modes while dead, but allowing to load a state; Implemented D2X' lighting code to D1X (faster, better, sexier - weeee); Try to hop over some errors regarding walls/doors in levels instead of using -1 indexes for arrays; Made the briefing text ptr a bit more failsafe in case the file is corrupt/non-standard; Made scores use the menu screen even in GAME OVER; Fixed bug in neighbour fields of Weapon Keys table; Added the Weapon Keys stuff to TABLE_CREATION; Fixed bug where D2X did not recall applied resolution in the resolutions menu; Simpler check to create DEMO_DIR; Seperated X/Y sensitivity for mouse and joystick; Flush controls when Automap toggles so keypress won't deactivate it again; Made FrameCount in Demos aligned to the Dropframe condition; Added KEy to ttoggle playback text off; Gracefully exit demo code if demo is corrupt; Removed that new percent counter because many old demos seem to have corrupted last frames; Closing endlevel data file if IFF error so the mission still can be freed; Fixed Cruising for keyboard which was not aligned to FPS correctly; Used mouse delta scaling in kconfig.c instead of mouse.c to not screw up when delta is requested in non-ingame situations - it actually belongs to the controls IMHO; Now support up to 8 joysticks; Changed some leftover malloc's to d_malloc and free to d_free 20081004 -------- d1x-rebirth.xcodeproj, arch/carbon/conf.h, tracker/client/tracker_client.c: Keep Xcode project up-to-date, look in 'SDL' directory for SDL.h main/paging.c: Page in overriding robot textures, like D2X-Rebirth 20081001 -------- main/physics.c: Update object segment after object position interpolation. This is always done in DEBUG, but not in RELEASE, where further movement would break at segment check 20080930 -------- main/console.c, main/collide.c, main/mglobal.c, main/multi.c, main/inferno.c, main/physics.c, main/aipath.c, main/render.c, main/fuelcen.c, main/ai.c, main/game.c, main/game.h, SConstruct, d1x.ini, maths/vecmat.c, arch/sdl/timer.c, arch/sdl/mouse.c, arch/sdl/digi.c, arch/sdl/digi_audio.c, arch/include/mouse.h: Added new function to calculate common timesteps; Increased MAXIMUM_FPS to 200 for release and 1000 for debug; Used fixed sim_time for do_physics_sim and Interpolating to ensure collisions stay accurate at high FPS; New code and faster code for dot products by The_Lion; Disabled Nice-FPS and common Frame-Loop if VSync is active; More accurate delta timer for mouse (consider overhead); Added SDL_(Un)LockAudio for old SDL Audio interface; General support for up to 16 mouse buttons; Code cleanup; Made some AI movement and Player shaking FPS-independent 20080818 -------- misc/dl_list.c, include/dl_list.h: Added dl_size(dl_list const *) and some minor const correctness. tracker/Protocol.txt: More thought on tracker protocol. tracker/{server/tracker_server.c, client/tracker_client.c}: More work on tracker code base. 20080812 -------- tracker/Protocol.txt: More thought on tracker protocol. tracker/{server/tracker_server.c, client/tracker_client.c}: More work on tracker code base. 20080810 -------- include/tracker/{tracker.h, Protocol.txt, client/tracker_client.c, server/tracker_server.c}: More work on tracker. SConstruct: Added PROGRAM_NAME to list of CPPDEFINES. Needed for tracker protocol's useragent submission. 20080727 -------- 2d/pcx.c: Fixed a compiler warning main/newdemo.c: Added some notes regarding a compiler warning raised here 20080726 -------- main/{console.c, wall.h, powerup.h, robot.h}: Fixed harmless warnings on no new line at end of source main/{config.c, config.h, menu.c, include/tracker/tracker.h, tracker/client/tracker_client.c: Added beginnings of game tracker feature. Available only in debug mode for now. SConstruct: Cleaned up build system a bit with prettier build messages, added a feature or two, and included tracker source 20080726 -------- d1x-rebirth.xcodeproj, main/netpkt.c, main/netpkt.h: Make network endian code more consistent with D2X, use PUT/GET_INTEL macros more, remove redundant no_cpp_precomp macro 20080720 -------- include/netdrv.h, main/netdrv_udp.c, main/netdrv_udp.h, main/netdrv.c, arch/linux/netdrv_ipx.c, arch/linux/netdrv_kali.c, arch/win32/netdrv_ipx.c: Fixed IPX default socket (typo); Using function pointer for IPX-based sockets instead of globals 20080715 -------- 2d/pcx.c, include/pcx.h, main/game.c, main/titles.c, main/titles.h: Add BALDGUY cheat for Mac data (see if anyone finds it ;-) ) 20080701 -------- arch/carbon/conf.h, D1X.make, d1x-Info.plist, d1xgl-Info.plist, d1x-rebirth.xcodeproj, English.lproj/InfoPlist.strings: Increment version number for Mac, update MPW makefile, ensure Get Info strings copy to bundle, use correct Mac OS X SDKs include/strutil.h, misc/strutil.c: Add snprintf for Mac OS 9 main/songs.c: Make sure the right audio CD track is played when starting a level include/physfsx.h, main/config.c: No using chdir for Mac OS 9 - it doesn't have it 20080617 -------- main/songs.c: start at track 1 and continue playing audio CD if it's not the original Mac one (this is how it worked before) 20080615 -------- main/gameseq.c, main/mission.c, main/newdemo.c, main/scores.c: Fixed scores write (wasn't PhysFS); Fixed PLAYING_BUILTING_MISSION in D1X; Better call for DoJasonInterpolate in demo code (hopefully) arch/sdl/digi_mixer.c, arch/sdl/rbaudio.c, include/inferno.h, include/rbaudio.h, main/game.c, main/songs.c: tidy up music keys, ALT-SHIFT-F9 ejects audio CDs 20080612 -------- README.txt, main/collide.c, main/multi.c, main/netdrv_udp.c, main/network.c, main/state.c: Improved Player relay for Endlevel status; Fixed leaving when UDP hosts leaves; Fixed multi_frame_calling while demos since demos can be Game_mode & GM_MULTI; Re-added lost collision fix between robots and reactor; Made state_defaut_item static so selected state slot stays selected arch/sdl/digi_mixer.c: Setting GameArg.SndNoSound to true if SDL_mixer init fails 20080605 -------- INSTALL.txt, arch/sdl/digi_mixer.c, arch/sdl/jukebox.c: Small doc update; Improved SDL_mixer / Jukebox handling if no resource (sound) is available 20080604 -------- main/newmenu.c, main/network.c, main/menu.c, main/menu.h, main/playsave.c, main/titles.c, main/kmatrix.c, main/scores.c, main/game.c, main/gauges.c, main/kconfig.c, main/credits.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, arch/include/jukebox.h: Generally increasing Menu rendering from 20 to 50 FPS; Allowed Fullscreen toggle in Pause menu and correctly releasing mouse; Fixed broken Death sequence timer; Fixed incorrect data offset for UDP player relay; Fixed crash in Multiplayer summary; Reworked player loading a little bit, making sure kconfig controls are all set; Some small Status bar correction; Implemented real Pause/Reume for Jukebox via SDL_mixer 20080602 -------- main/inferno.c: Added d1xrdata.zip for custom data arch/sdl/jukebox.c: Only stop music at jukebox_stop() if MIDI jukebox_loaded - otherwise user can stop Jukebox with keys but not start it again 20080601 -------- include/args.h, main/inferno.c, main/hud.c, main/game.c, main/gamecntl.c, misc/args.c, d2x.ini, README.txt, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/digi_audio.c, arch/win32/include/hmpfile.h, arch/win32/hmpfile.c: Using Windows code to play HMP files on Windows build; Fixed Jukebox keys in help screen; Allow -noredundancy in Singleplayer; Fixed processing of Console keys if Console is not active; Added Multiplayer hints to README; Made INI wrapping safer and more accurate 20080528 -------- arch/sdl/rbaudio.c, main/songs.c: allow an audio CD to be played if it's inserted after D1X is launched, hopefully find the first audio CD if multiple CDs are inserted 20080525 -------- arch/sdl/digi_mixer.c, arch/sdl/jukebox.c, main/kconfig.c, main/morph.h: Set sound distance to 0 for HUD sound taunts; Making Jukebox not crash if -nosound is enabled (should stop Jukebox since no digi system enabled); Lowered mouse axis speed a bit again; Increasing MAX_VECS to 5000 20080524 -------- arch/sdl/jukebox.c, arch/sdl/rbaudio.c, d1x-rebirth.xcodeproj, include/rbaudio.h, main/automap.c, main/config.c, main/config.h, main/credits.c, main/game.c, main/kconfig.c, main/kmatrix.c, main/menu.c, main/network.c, main/newmenu.c, main/scores.c, main/songs.c, main/songs.h, SConstruct: Add audio CD support to D1X, fix associated bugs 20080522 -------- main/menu.c: Added a new set of preset resolutions 20080521 -------- arch/ogl/gr.c, arch/sdl/mouse.c, main/game.h: Implmented filtered mouse delta reading SConstruct, INSTALL.txt, README.txt: Updated docs 20080520 -------- main/kconfig.c: Decreasing divisor for mouse axis reading - making mouse sensitivity practically much higher 20080519 -------- main/mission.c, main/mission.h: Added support for another registered D1 HOG with different patching order... damn you PARALLAX! d1x.ini, arch/sdl/digi_mixer.c, include/args.h, main/gamefont.c, main/inferno.c, misc/args.c: Added -nomusic ability for SDL_mixer API; Added -gl_fontfixwidth to scale fonts with fixed aspect on widescreen resolutions, scaled to height 20080518 -------- include/physfsx.h, main/config.c: set "Jukebox" as the default jukebox path, for Mac OS 9 look for d1x.ini outside the app bundle main/game.c, main/songs.c: Reworked keys for song changing a bit; Added Song control keys to help menu 20080516 -------- main/multi.c, main/multibot.c, main/netpkt.c, main/network.c: fix remaining endian bugs in network code, now it works on the Mac d1x.ini, include/args.h, main/config.c, main/config.h, main/inferno.c, main/menu.c, misc/args.c: remember the last IP address entered for UDP instead of parsing -ip_hostaddr 20080510 -------- main/playsave.c: use atoi instead of sscanf for plx reading, so the setting for showing the reticle is read properly on big endian computers 20080508 -------- main/newmenu.c, main/render.c, arch/sdl/key.c, arch/include/key.h: Some code improvements and small fixes 20080507 -------- include/args.h, main/newmenu.c, main/multi.c, main/multi.h, main/inferno.c, main/menu.c, main/netdrv_udp.c, main/game.c, misc/args.c, d1x.ini, ui/inputbox.c, ui/menubar.c, arch/sdl/digi_mixer.c, arch/sdl/jukebox.c, arch/sdl/key.c, arch/include/jukebox.h, arch/include/key.h: Return unicode characters in key_to_ascii for non-EN keyboard layouts; Fixed sound menu issue if not compiled with SDL_mixer; switched -ip_norelay to -ip_relay since it's not tested enough; Renamed jukebox_free() to jukebox_unload() to stay with naming-convention 20080502 -------- include/args.h, main/inferno.c, main/menu.c, main/songs.c, main/config.c, main/config.h, main/game.c, misc/args.c, SConstruct, d1x.ini, arch/ogl/gr.c, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, arch/win32/hmpfile.c, arch/include/jukebox.h: Extended Jukebox capabilities for looping and continous playing and added jukebox_free() which allows calling jukebox_load() being able to load a new directory; Added Jukebox options to sound options menu; Removed loop hack for Windows MIDI playback; SDL_mixer implementation can now be used for Windows build as well 20080427 -------- main/console.c: make sure it doesn't try to write to gamelog.txt after it's closed 20080424 -------- arch/sdl/digi_mixer.c, D1X.make, iff/iff.c, include/args.h, include/ogl_init.h, include/u_dpmi.h, main/ai.c, main/bmread.c, main/config.h, main/game.c, main/gamesave.c, main/gameseq.c, main/hash.c, main/inferno.c, main/menu.c, main/newdemo.c, main/newmenu.c, main/piggy.c, main/playsave.c, main/playsave.h, main/state.c, main/titles.c, misc/args.c, texmap/tmapppc.a: get it to work for Mac OS 9 20080422 -------- arch/ogl/gr.c, arch/sdl/gr.c, include/gr.h, main/config.c, main/config.h, main/menu.c: Added function gr_set_attributes to change Options like Texture Filtering and SDL_GL attributes while runtime (if supported); Added 4x Multisample support 20080421 -------- main/console.c, main/custom.c, main/inferno.c, main/menu.c, main/gamesave.c, main/config.c, main/config.h, main/game.c, misc/args.c, d1x.ini, arch/ogl/gr.c, arch/sdl/timer.c, arch/win32/netdrv_ipx.c: Reworked timer_delay2() and calc_frame_time() to be more accurate and CPU-friendly; -nicefps replayced by -nonicefps to disable sleeping for calc_frame_time; Implemented VSync via SDL; Fixed compilation issues; Code cleanup main/console.c: Hack to force DOS-style newlines for _WIN32 in gamelog.txt 20080419 -------- include/ogl_init.h, include/gr.h, include/strutil.h, include/internal.h, main/network.c, main/menu.c, main/game.c, d1x-rebirth.xcodeproj/project.pbxproj, SConstruct, arch/ogl/ogl.c, arch/ogl/gr.c, arch/sdl/joy.c, arch/sdl/gr.c, arch/carbon/conf.h: Made joy_flush also resetting button state; Improved glReticle; Implemented Fallback resolution if SDL may fail; Code cleanup 20080414 -------- main/network.c: fix network bug where it got confused about the Function_mode and gave up 20080413 -------- include/args.h, main/newmenu.c, main/collide.h, main/network.c, main/multi.c, main/multi.h, main/inferno.c, main/menu.c, main/menu.h, main/playsave.c, main/playsave.h, main/object.c, main/hud.c, main/weapon.c, main/hostage.c, main/newdemo.c, main/config.c, main/gameseq.c, main/endlevel.c, main/ai.h, main/game.c, main/gauges.c, main/game.h, main/kconfig.c, main/kconfig.h, misc/args.c, d1x.ini, arch/ogl/ogl.c, arch/ogl/gr.c, arch/sdl/joy.c, arch/include/joy.h: Added structure for values saved in PLR/PLX files; Added most common command-line options to options menu main/laser.c, main/menu.c, main/playsave.c: Reverted homers turn_radius again to respect higher difficulty levels; Added PRShot to menus; Fixed typo in OglAlphaEffects saving main/cntrlcen.c, main/collide.c, main/hudmsg.h, main/object.c, main/physics.c: Fixing collision bugs; Cleaning hudmsg.h; Solving death sequence timer without GameTime and removed another global 20080408 -------- d1x-rebirth.xcodeproj, include/cfile.h, main/bmread.c, main/inferno.c, main/newmenu.c, misc/error.c, ui/gadget.c, ui/window.c: show a messagebox if there's an error and graphics are initialised, update Xcode project 20080406 -------- d1x.ini, SConstruct, main/config.c, main/config.h, main/console.c, main/console.h + various: Implemented Console-style game logging system to print graphics, to stdout and gamelog.txt; Added structure to keep values for descent.cfg; Added aspect and Texture Filtering to descent.cfg; Removed mono code - printing important stuff over console; Removed some obsolete or very common defines; Code cleanup and small fixes 20080402 -------- main/automap.c, main/gamefont.c, main/gamefont.h, main/inferno.c, main/inferno.h: fix up the Mac data automap layout 20080331 -------- main/songs.c: fix divide by 0 bug when there is no music available 20080330 -------- main/piggy.c: add support for Mac demo sounds 20080327 -------- d1x-rebirth.xcodeproj, main/bmread.c, main/piggy.c: add support for Mac sounds (converted to RAW format), update Xcode project 20080325 -------- include/loadgl.h, main/credits.c, main/gameseq.c, main/inferno.c, main/inferno.h, main/kmatrix.c, main/menu.h, main/mglobal.c, main/newmenu.c, main/playsave.c, main/titles.c: Added definitions for OpenGL fucntions which might not be included in system headers; Use more HiRes content from dxx.zip; Removed briefings palette hacks; Menu right border shadow was too wide; Corrected reading for some PLX content which seemed not to work on all archs 20080323 -------- arch/sdl/digi.c, arch/sdl/digi.h, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer.h, arch/sdl/digi_mixer_music.c, arch/sdl/digi_mixer_music.h, include/strutil.h, main/songs.c, misc/strutil.c: detect the number of songs actually available if no descent.sng file (max 22) SConstruct, main/game.c, main/gameseq.c, main/kconfig.c, main/laser.c, main/menu.c, main/newmenu.c, main/playsave.c, main/powerup.c, main/weapon.c: Implemented D2X code for wepaon cycling and reordering; Added lock status for mouse axis weapon cycling because of scaled mouse delta; Due to player feedback (any my opinion) making homer turn rate smaller to make them a bit harder to dodge; Preventing write of player data while Demo playback; Small code cleanup and corrections 20080322 -------- d1x-rebirth.xcodeproj, INSTALL.txt, SConstruct: make compile instructions clearer for Windows and Mac users, for Mac OS X don't use Sharepath when using SConstruct, handle warnings differently in Xcode main/gamefont.c, main/mission.h: scale Mac fonts correctly 20080321 -------- 2d/palette.c, arch/ogl/gr.c, arch/ogl/ogl.c, arch/sdl/gr.c, include/gr.h, include/palette.h, main/automap.c, main/automap.h, main/credits.c, main/endlevel.c, main/game.c, main/gameseq.c, main/inferno.c, main/kconfig.c, main/kmatrix.c, main/menu.c, main/network.c, main/newmenu.c, main/paging.c, main/scores.c, main/switch.c, main/titles.c, ui/window.c: Simplification of palette code; Properly screen clearing in SDL-only build when palette changes; Removed obsolete functions like gr_update (replaced by gr_flip), gr_palette_fade_in/out, gr_palette_clear; Added functionality to render Automap while menu display as well; Improved blocking of some controls code while Automap active; Fixed some compiler warnings include/physfsx.h: allow d1x.ini to stay with the binary for *NIX systems, with Mac OS 9 don't put user-created files inside the .app bundle 20080316 -------- 2d/bitblt.c, 2d/rle.c, arch/ogl/ogl.c, include/gr.h, include/rle.h, main/game.c, main/gauges.c, main/gauges.h, main/inferno.c, main/piggy.c, main/piggy.h, main/titles.c: add support for Mac pigfile (which doesn't include sounds yet) 20080314 -------- main/network.c: add prototype for show_game_stats to remove warning d1x-rebirth.xcodeproj: update sourcefile list in Mac Xcode project file 20080313 -------- main/render.c: fix potential bug where show_reticle parameters mismatch 20080308 -------- main/aipath.c, main/collide.c, main/fvi.c, main/game.c, main/gauges.c, main/mission.c, main/netdrv.c, main/newdemo.c, main/newdemo.h, main/newmenu.c, main/object.c: Fixed some memory issues; Fixed some HUD element alignment; Only send NetDrv packets if NetDrvInstalled is true; Fixed demo glitches; Actually using Game_mode in demos to make Newdemo_game_mode hacking obsolete main/game.c: Handle Multi message input before HandleDeathKey to chat while dead 20080228 -------- 2d/font.c, arch/ogl/gr.c, arch/ogl/ogl.c, main/game.c, main/game.h, main/gameseq.c, main/gauges.c, main/hud.c, main/mission.c, main/network.c, main/newmenu.c, main/paging.c, main/state.c: Fixed wrong font width spacing, -gl_prshot, mission loading, null-terminatinon in several menus, cockpit glitch; Improved gl_reticle, -noredundancy; Some code cleanup 20080224 -------- main/newdemo.c: make sure the right error message is shown if it can't open a demo include/args.h, include/gr.h, main/newmenu.c, main/newmenu.h, main/network.c, main/multi.c, main/inferno.c, main/gamefont.c, main/menu.c, main/gamefont.h, main/netdrv_udp.c, main/playsave.c, main/titles.c, main/kmatrix.c, main/controls.c, main/paging.c, main/hud.c, main/state.c, main/reorder.c, main/slew.c, main/gameseq.c, main/scores.c, main/automap.c, main/game.c, main/gauges.c, main/game.h, main/kconfig.c, main/credits.c, misc/args.c, 2d/font.c, SConstruct, d1x.ini, arch/ogl/ogl.c, arch/ogl/gr.c, arch/sdl/gr.c: Reworked fonts routines - makes easier to expand and scale correctly; Reworked menus with better border scaling, improved rendering and cleanups; Improved font priniting ingame, better alignment; Reworked Netgame list; Real Doublebuffering in SDL-mode; Removed old and unused sources main/playsave: Fixed error in writing PLR-file since PHYSFS_close returns non-zero in success instead of zero like fclose 20080221 -------- main/inferno.c, main/newmenu.c, main/titles.c: add support for Macintosh splash screens and menu backgrounds in descent.hog, but not fonts (yet) 20080217 -------- d1x-rebirth.xcodeproj, main/game.c, main/newmenu.c: get SDL Video build to work again misc/hmp2mid.c: don't try and free mid_track_buf if it isn't allocated, if midi conversion doesn't work 20080213 -------- main/piggy.c, main/piggy.h: fix undefined function warning with piggy_read_sounds (whoops) iff/iff.c: remove redundant iff functions 20080212 -------- main/endlevel.c: make sure a briefing isn't interpreted as an endlevel sequence file, preventing an in-game warning 20080211 -------- d1x-rebirth.xcodeproj, include/strutil.h, main/bm.c, main/bm.h, main/bmread.c, main/digiobj.c, main/inferno.c, main/piggy.c, main/piggy.h, main/polyobj.c, main/songs.c, main/text.c, main/text.h, misc/strutil.c, SConstruct: support PC shareware files in full version build, make game data loading code easier to follow 20080129 -------- SConstruct, arch/include/digi_audio.h, arch/include/digi_mixer.h, arch/include/digi_mixer_music.h, arch/include/event.h, arch/include/joy.h, arch/include/joystick.h, arch/include/jukebox.h, arch/include/key.h, arch/include/mouse.h, arch/linux/include/music.h, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/sdlgl.c, arch/sdl/mouse.c, include/internal.h, include/loadgl.h, include/ogl_init.h, main/kconfig.c: Cleanung up arch/ a little bit; Added mouse delta time interval for more more accurate reading at high FPS SConstruct, main/netdrv_udp.c, main/netdrv_udp.h, main/newmenu.c: Renaming udp.* to netdrv_udp.c to fit naming convention; Small menu ui fixes 20080126 -------- arch/sdl/digi_mixer_music.c: allow custom MIDI in add-on hogs to be used without caching everything 20080125 -------- main/collide.c, main/custom.c, main/kconfig.h, main/newdemo.c, main/powerup.c: Fixed small compiling issues 20080124 -------- INSTALL.txt, main/game.c, main/mission.h, main/network.c: Updated Docs - Data files must be lowercase; Fixed small Multiplayer issues 20080123 -------- d1x.ini, INSTALL.txt, SConstruct, 2d/font.c, 2d/canvas.c, 2d/bitmap.c, 2d/rle.c, 2d/pcx.c, arch/linux/hmiplay.c, arch/ogl/ogl.c, arch/ogl/gr.c, arch/sdl/digi_mixer_music.c, arch/sdl/joy.c, arch/sdl/include/digi_mixer_music.h, arch/sdl/jukebox.c, arch/sdl/gr.c, arch/win32/hmpfile.c, editor/macro.c, editor/medsel.c, editor/med.c, editor/autosave.c, iff/iff.c, include/args.h, include/hmp2mid.h, include/pstypes.h, include/ignorecase.h, include/cfile.h, include/error.h, include/strio.h, include/u_mem.h, include/physfsx.h, main/gameseg.c, main/custom.c, main/newmenu.c, main/fvi.c, main/text.c, main/network.c, main/text.h, main/multi.c, main/multi.h, main/inferno.c, main/gamefont.c, main/menu.c, main/inferno.h, main/playsave.c, main/titles.c, main/titles.h, main/bmread.c, main/piggy.c, main/render.c, main/state.c, main/gamesave.c, main/newdemo.c, main/config.c, main/gameseq.c, main/hash.c, main/gameseq.h, main/altsound.c, main/ai.c, main/scores.c, main/endlevel.c, main/terrain.c, main/polyobj.c, main/game.c, main/mission.c, main/mission.h, main/credits.c, mem/mem.c, misc/ignorecase.c, misc/hmp2mid.c, misc/strio.c, misc/error.c, misc/dl_list.c, misc/args.c, ui/radio.c, ui/menu.c, ui/window.c, ui/inputbox.c, ui/keypad.c, ui/file.c, ui/checkbox.c, ui/menubar.c, ui/lfile.c, ui/gadget.c: Implemented PhysFS support; Implemended D2X memory functions; Code cleanups 2d/clip.h, 2d/line.c: fix name conflict 'FSCALE' on Mac OS X d1x-rebirth.xcodeproj: add Xcode 2.2 project for Mac OS X 20080113 -------- main/network.c: fix typo causing compiler error on bigendian computers 2d/font.c, 2d/pcx.c, 3d/interp.c, cfile/cfile.c, include/cfile.h, include/pstypes.h, main/bm.c, main/cntrlcen.c, main/cntrlcen.h, main/custom.c, main/custom.h, main/effects.c, main/effects.h, main/fuelcen.c, main/fuelcen.h, main/gamemine.c, main/gamesave.c, main/loadrl2.c, main/newdemo.c, main/piggy.c, main/piggy.h, main/playsave.c, main/polyobj.c, main/powerup.c, main/powerup.h, main/robot.c, main/robot.h, main/scores.c, main/switch.c, main/switch.h, main/vclip.c, main/vclip.h, main/wall.c, main/wall.h, main/weapon.c, main/weapon.h: complete bigendian support, without touching network code 2d/font.c: make special characters print for platforms where a char is signed by default arch/ogl/gr.c, arch/ogl/include/ogl_init.h, arch/ogl/sdlgl.c, include/args.h, main/args.c, main/inferno.c, main/menu.c, main/newdemo.c: Removed SDL Gammaramp code (obsolete); Improvements on Demo code include/pstypes.h, include/strutil.h, main/fuelcen.c, main/fuelcen.h, main/gamemine.c, main/gamesave.c, main/gamesave.h, main/gameseq.h, main/inferno.h, main/loadrdl.h, main/loadrl2.c, misc/strutil.c, SConstruct: merge loadrl2.c into gamemine.c and gamesave.c 20080110 -------- arch/sdl/jukebox.c, arch/sdl/include/jukebox.h, arch/sdl/digi_mixer_music.c; fixed looping jukebox music when it shouldn't (at end of level) 20080108 -------- SConstruct, 2d/font.c, include/args.h, include/byteswap.h, include/netdrv.h, main/args.c, main/gameseq.c, main/gameseg.c, main/menu.c, main/multi.c, main/multi.h, main/multibot.c, main/netdrv.c, main/netlist.c, main/netpkt.c, main/netpkt.h, main/network.c, main/network.h, main/newdemo.c, main/object.h, main/udp.c: Added BigEndian-related multiplayer/network code (unfinished); Re-Added IPX Socket option to Host menu for IPX games; Removed ForceVersionCheck global - conditions with driver->type; Merged netmisc.* and netpkt.*; Handling host disconnect for UDP games in network.c main/menu.c, main/newmenu.c, main/newmenu.h: Safe timer rollover in menu idle-demo function; Reintroduced menu shortcuts; Implemented support for menu scrolling if nitems > 15 20080103 -------- 2d/bitmap.c, 2d/font.c, arch/carbon/conf.h, arch/ogl/gr.c, arch/ogl/include/ogl_init.h, arch/sdl/digi_mixer_music.c, arch/sdl/include/music.h, arch/sdl/jukebox.c, iff/iff.c, include/d_glob.h, include/d_io.h, include/error.h, include/pstypes.h, include/strutil.h, include/u_mem.h, main/args.c, main/game.c, main/gameseq.c, main/inferno.c, main/newdemo.c, misc/d_glob.c, misc/strutil.c, SConstruct, texmap/scanline.c: get D1X to build for Mac OS X, conditionals for Mac OS 9 20080102 -------- 2d/ibitblt.c, 2d/palette.c, arch/linux/joystick.c, arch/linux/linuxnet.c, arch/sdl/digi.c, arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, arch/sdl/include/joy.h, arch/sdl/include/key.h, arch/sdl/include/mouse.h, arch/sdl/joydefs.c, arch/win32/include/joy.h, arch/win32/include/mouse.h, arch/win32/winnet.c, cfile/cfile.c, include/compare.h, include/gr.h, include/iff.h, include/ipx_drv.h, include/maths.h, include/pstypes.h, include/rle.h, include/timer.h, include/u_dpmi.h, main/altsound.c, main/bm.c, main/bmread.c, main/config.c, main/console.c, main/credits.c, main/custom.c, main/d_conv.c, main/digi.h, main/gameseg.h, main/ipx_drv.c, main/kconfig.c, main/kconfig.h, main/kmatrix.c, main/loadrdl.h, main/multi.c, main/netlist.c, main/netmisc.c, main/netpkt.c, main/network.c, main/newmenu.c, main/object.h, main/piggy.c, main/scores.c, main/segment.h, main/songs.c, main/titles.c, mem/mem.c, ui/button.c, ui/checkbox.c, ui/file.c, ui/gadget.c, ui/icon.c, ui/inputbox.c, ui/keypad.c, ui/keypress.c, ui/keytrap.c, ui/lfile.c, ui/listbox.c, ui/menu.c, ui/menubar.c, ui/message.c, ui/mouse.c, ui/popup.c, ui/radio.c, ui/scroll.c, ui/ui.c, ui/uidraw.c, ui/userbox.c, ui/window.c: rename types.h to pstypes.h to avoid name conflict with Mac OS 9's MrC (it doesn't respect the difference between project and system headers) SConstruct, arch/linux/netdrv_ipx.c, arch/linux/netdrv_kali.c, arch/ogl/ogl_init.h, arch/win32/netdrv_ipx.c, main/inferno.c, main/menu.c, main/mission.h, main/netdrv.c, main/netdrv.h, main/netlist.c, main/netpkt.c main/netpkt.h, main/network.c, main/udp.c, main/udp.h: Cleaned/Rewritten/Renamed lower level network layer to make it (look) less IPX-oriented 20080101 -------- arch/carbon/conf.h, arch/carbon/descent.r, arch/carbon/SDL_main.c, arch/cocoa/d1x-rebirth.icns, arch/cocoa/SDLMain.h, arch/cocoa/SDLMain.m, arch/cocoa/tool_bundle.py, d1x-Info.plist, d1xgl-Info.plist, English.lproj/InfoPlist.strings: add Mac source files 20071229 -------- arch/sdl/digi.c, main/ai.c, main/game.h, main/gameseq.c, main/inferno.c, main/laser.c, main/laser.h, main/menu.c, main/multi.c, main/multi.h, main/multibot.c, main/multibot.h, main/object.c, main/object.h, main/physics.c, main/titles.c, main/wall.c: Code cleanup - old/unused/obsolete multiplayer code and more 20071223 -------- include/ipx.h, main/credits.c, main/inferno.c, main/laser.c, main/network.c, main/network.h, main/piggy.c, main/powerup.c: Fixed compiler error because of removed header file; Removed struct network_d1xplayer_info - obsolete; Allocated memory for all sequence_packet's; Moved piggy_close() and sdl_close() to end of main() - replacing atexit; Rendering credits with timer_delay2 at constant 25FPS and save CPU; Fixed -playermessages 20071217 -------- d1x.ini, SConstruct, arch/linux/ipx_bsd.c, arch/linux/ipx_kali.c, arch/linux/linuxnet.c, arch/win32/ipx_win.c, arch/win32/winnet.c, include/args.h, include/ipx_drv.h, main/args.c, main/inferno.c, main/ipx_drv.c, main/kconfig.c, main/menu.c, main/netlist.c, main/network.c, main/network.h, main/scores.c, main/udp.c, main/udp.h: Implemented new UDP/IP interface with Server-Relay (for firewalled users) and IPv6 compability; Fixed memory issues; If arguments -gl_mipmap and -gl_trilinear used both, always select -gl_trilinear 20071124 -------- main/hud.c: Fixed new redundancy HUD messages check - made it more strictly 20071123 -------- main/aipath.c, main/fireball.c, main/titles.c: Fixed some memory problems; Adjusted timer_delay2 for robot briefings 20071121 -------- arch/sdl/key.c, arch/sdl/timer.c, include/timer.h, main/game.c, main/kconfig.c, main/kmatrix.c, main/netlist.c, main/newmenu.c, main/scores.c, main/titles.c: Introduced timer_delay2 as replacement for timer_delay to sleep according to given FPS rate considering calc time between frames 20071106 -------- main/config.c, main/game.c, main/game.h, main/menu.c, main/newdemo.c: Correctly saving Reverse Stereo setting; Added Demo playback help keys; aligned Demo recording to 20 frames per second to save lots of hard drive space 20071105 -------- arch/sdl/jukebox.c: Fixed crash on absent or invalid jukebox directory 20071101 -------- main/collide.c: Data types correction 20071031 -------- d1x.ini, SConstruct, arch/linux/linuxnet.c, arch/ogl/gr.c, arch/win32/winnet.c, include/args.h, main/args.c, main/collide.c, main/game.c, main/hudmsg.c, main/inferno.c, main/kconfig.c, main/laser.c, main/menu.c, main/multi.c, main/multi.h, main/multipow.h, main/netlist.c, main/network.c, main/state.c, main/state.h: Improvements for -gl_prshot; Improved show_netgame_info(); Removed obsolete multisave code; Removed mekh stuff and wide cleanings in whole multi code; Incremented MULTI_PROTO_D1X_VER (for version checks in the future if needed); Renamed 'D1X-only game' to 'Version Check' main/songs.c: Implemented Hack for broken descent.sng produced by patching descent.hog v1.0 to v1.5 20071029 -------- main/credits.c, main/newmenu.c: Memory stuff 20071028 -------- arch/ogl/ogl.c, include/args.h, main/args.c, main/collide.c, main/fuelcen.c, main/game.c, main/gameseq.c, main/gauges.c, main/hud.c, main/inferno.c, main/laser.c, main/mglobal.c, main/network.c, main/powerup.c: Fixed problems with GameTime wraparound - delay sounds, cloak, invulnerability, ping; Added debug key to Reset GameTime for testing; Removed -gl_vidmem; Cheat-code cleanup; Some HUD message redundancy main/hud.c: For HUD messages redundancy check, compare all messages and check if message already printed and is a typical "ALREADY HAVE" message - waste them if so 20071018 -------- d1x.ini, 2d/bitblt.c, 2d/box.c, 2d/rle.c, arch/ogl/gr.c, arch/ogl/ogl.c, include/args.h, include/rle.h, main/args.c, main/game.c, main/gauges.c, main/inferno.c, main/menu.c: Small fixes; Code cleanup; Implemented PR-Screenshot feature 20071014 -------- arch/sdl/digi_audio.c, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/jukebox.c, include/args.h, main/args.c, main/game.h, main/inferno.c: Set SOUND_BUFFER_SIZE for SDL_mixer to 1024 to minimize delay; Removed MIDI-existance check and store all music to Music/ subdirectory of writedir - keeps clean if user has tons of levels; Added SDL_mixer command-line help output; Implemented new way to read command-line args main/game.c: Reworked Pause-screen 20071012 -------- main/ip_base.cpp: Fixed port deformation while sending handshake main/inferno.c: Fixed some command-line options SConstruct: micro version now specified as the "micro" scons flag 20071008 -------- main/game.c, main/inferno.c, main/object.c, main/playsave.c: Improvements for Cockpit mode save; Fixed -pilot switch 20071007 -------- main/collide.c, main/laser.c: Changed collision handling between robots and controlcen; Aligned constant sounds to GameTime; Using turn radius of 0x0024*F1_0 for all homing objects while not aligning smart blobs to movement vector main/newdemo.c: Reset Rear_view at beginning and end of demo playback 20071006 -------- arch/ogl/ogl.c, main/game.c, main/gauges.c, main/gauges.h: Not rendering additional transparency cockpit display anymore to ensure compability with custom cockpits; Improved overlay functions for cockpit elements d1x.ini, include/args.h, main/args.c, main/inferno.c, main/playsave.c: Readded -notitles switch; Removed use of tempfile for PLX writing 20071001 -------- main/game.c, main/kconfig.c, main/titles.c: Added line_scpacing in netgame info screen for every not-connected player to keep strings below player table in fixed position; Fixed memleak in kconfig code; Fixed show_title_screen function to cycle correctly 3 seconds or until broken by keypress 20070930 -------- SConstruct, arch/sdl/digi_audio.c: Moved Windows midi functions to digi_audio_* functions 20070929 -------- INSTALL.txt, README.txt, SConstruct, arch/sdl/digi_audio.c, arch/sdl/event.c, arch/sdl/gr.c, arch/sdl/joy.c, arch/sdl/key.c, main/config.c, main/game.c, main/kconfig.c, main/menu.c, main/newmenu.c, main/scores.c: Updated docs; Removed GP2X support since I won't support this device anymore 20070928 -------- d1x.ini, include/args.h, main/args.c, main/gameseq.c, main/inferno.c, main/multi.c, main/newmenu.c, main/playsave.c: main/state.c: Implemented -use_players_dir 20070927 -------- main/game.c: Removed line_spacing for not connected players in Netgame info screen 20070926 -------- main/SConstruct, main/game.c, main/gauges.c, main/multi.c, main/network.c, main/network.h, main/nncoms.c: Small fixes for new netgame info screen; Doing PING routines D2X-way while trying to keep compability to other D1X versions 20070924 -------- main/newmenu.c: Removed key shortcuts for menus 20070921 -------- most files: executable flag removed main/digi.h: restored previous value of SOUND_MAX_VOLUME 20070920 -------- d1x.ini, SConstruct, include/args.h, main/newmenu.c, main/network.c, main/text.h, main/network.h, main/multi.h, main/inferno.c, main/netlist.c, main/game.c, main/ipx_drv.c, main/args.c: Code-cleanup; Implemented new multi profile feature main/titles.c: Removed briefing text shadows code 20070918 -------- SConstruct, main/inferno.c, main/digi.h, arch/sdl/include/digi_audio.h, arch/sdl/include/digi_mixer_music.h, arch/sdl/include/digi_mixer.h, arch/sdl/jukebox.c, arch/sdl/digi.c, arch/sdl/digi_mixer.c, arch/sdl/digi_mixer_music.c, arch/sdl/digi_audio.c : huge refactoring of sound system using function pointers, to allow sound backend selection at runtime and provide a common interface (digi.c) include/args.h, main/args.c : handle SDL_mixer-specific args include/hmp2mid.h, misc/hmp2mid.c : moved hmp2mid to misc/, for better organisation and consistency between D1X and D2X 20070913 -------- Sconstruct, main/game.c, main/inferno.c, main/mlticntl.c, main/mprofile.c, main/multi.c, main/network.c, main/network.h: Code Re-formatting; Preventing Redundancy in Restricted-game joining and leaving players (packet redundancy); Removed Network master menu (and mlticntl code) due to compatibility to older games; Using D2X code for restricted games; Expanded Game-help screen 20070908 -------- main/command.c, main/game.c, main/gauges.c, main/multi.c, main/multiver.c, main/network.c, /main/network.h: Added complex netgame information screen (key PAUSE), Removed ping commands because ping handled in new screen 20070905 -------- d1x.ini, 2d/font.c, include/args.h, main/args.c, main/command.c, main/game.c, main/gameseq.c, main/gameseq.h, main/inferno.c, main/multi.c: Removed handicapping remnants, Removed -msgcolorlevel, color names in Multi-messages to Player- or Team-color 20070903 -------- 2d/font.c, main/multi.c: Fixed embedded color strings 20070831 -------- main/game.c, main/gauges.c: HUD alignment improvements 20070830 -------- d1x.ini, include/args.h, main/args.c, main/gauges.c, main/inferno.c: Added command-line option to disable reticle 20070829 -------- main/titles.c: Use right palette after briefings end to make sure nothing gets messed up main/physics.c: Apply BUMP_HACK on walls only 20070828 -------- d1x.ini, 2d/bitblt.c, include/args.h, main/args.c, main/automap.c, main/credits.c, main/inferno.c, main/newmenu.c, main/piggy.c, main/titles.c: Fixed some mem-leaks; Made show_fullscr() use ogl_ubitmapm_cs(); Removed use of glScissor for menus - using Blitting; Code cleanup SConstruct, arch/ogl/gr.c: If sdl_only=1 do not use Assembly code by default because of poor portability - switch asm=1 necessary now; Removed final remnants of glScissor 20070826 -------- main/game.c, main/multi.c: Improved CPU cycles sleeping for -nicefps - moved out of main frame calc loop and taking care of 10ms timer inaccuracy main/hud.c: Preventing redundancy of doubled messages correctly 20070821 -------- main/ip_base.h, main/ipclient.h: Fixed some compiler warnings 20070809 -------- d1x.ini, include/args.h, main/args.c, main/inferno.c, main/menu.c: Added -ip_hostaddr argument to specify a host IP address via command-line/INI main/gameseq.c, main/menu.c: Fixes and improvements on -ip_hostaddr; Fixed paltte bug in SDL build main/ipbase.cpp, main/ipbase.h, main/ipclient.cpp, main/ipclient.h, main/multi.c: Some debugging-related cleanups, Fixed memleak 20070808 -------- main/config.c, main/game.c, main/gameseq.c, main/menu.c, main/polyobj.c, main/titles.c, main/titles.h: Set default value for Game_screen_mode which is necessary if there's no config file yet; Made resolution switching more failsafe by not allowing resolutions below 320x200; Cleaned up briefings code (I hope so) main/game.c, main/menu.c: Fixed excessive use of set_screen_mode; Menu fixes 20070727 -------- d1x.ini, main/config.c, main/inferno.c, main/game.c, main/game.h, main/gameseq.c, main/menu.c, main/playsave.c: Cleanup in Config- and PLX-code; Saving Resolution in Config file so it will apply directly at game-init; Removed seperated resolution mode for menus, SCREEN_MENU now always uses Game_screen_mode; Last FindArg cleanups 20070723 -------- arch/ogl/gr.c, arch/ogl/include/ogl_init.h, arch/ogl/ogl.c, arch/sdl/gr.c, include/args.h, main/args.c, main/inferno.c: FindArg cleanup - GL-Debug and SDL arguments 20070722 -------- include/args.h, main/network.c, main/network.h, main/multi.h, main/inferno.c, main/menu.c, main/mprofile.c, main/automap.c, main/game.c, main/ipx_drv.c, main/game.h, main/args.c, arch/linux/linuxnet.c, arch/win32/winnet.c: Code cleanup and small fixes main/multi.h, main/state.c: Removed -multisave argument, deactivated feature as default (multi.h define) - broken, not sure if it's worth to fix arch/linux/hmiplay.c, arch/ogl/sdlgl.c, include/args.h, main/altsound.c, main/args.c, main/digi.h, main/digiobj.c, main/inferno.c, main/ipserver.cpp, main/piggy.c, main/polyobj.c: Even more FindArg cleanups 20070718 -------- SCsonstruct, arch/ogl/gr.c, arch/ogl/include/ogl_init.h, arch/ogl/ogl.c, include/args.h, include/gr.h, include/ipx_drv.h, main/args.c, main/game.c, main/inferno.c, main/ipx_drv.c, main/menu.c, main/piggy.c, main/render.c, main/text.c: Cleaned up more FindArg's - general Debug Options; Cleanups main/cntrlcen.c, main/controls.c, main/game.c, main/gameseq.c, main/inferno.c, main/m_inspak.c, main/multi.c, main/multi.h, main/netlist.c, main/network.c, main/object.c, main/physics.c, main/physics.h: FindArg cleanup; Removed remnants of Observer-mode include/args.h, main/args.c, main/bmread.c, main/inferno.c, main/piggy.c, main/render.c, mem/mem.c: Cleanups 20070716 -------- d1x.ini, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, arch/sdl/gr.c, include/args.h, include/gr.h, main/args.c, main/automap.c, main/game.c, main/gamefont.c, main/gauges.c, main/inferno.c, main/menu.c, main/newmenu.c: Cleaned up more FindArg's - (most important) OpenGL Options main/automap.c, main/game.c: Fixing duplicated gr_toggle_fullscreen() main/fuelcen.c, main/game.c, main/game.h, main/laser.c: Removed unused RealFrameTime; Removed FPS-dependent Homing-tracking code d1x.ini, 2d/font.c, include/args.h, main/args.c, main/ban.c, main/game.c, main/hud.c, main/inferno.c, main/inferno.h, main/ip_base.cpp, main/ipclient.cpp, main/ipx_drv.c, main/menu.c, main/network.c: Cleaned up more FindArg's - Networking Options; Some fixes 20070715 -------- Sconstruct, d1x.ini, arch/win32/midi.c, include/args.h, main/args.c, main/inferno.c: Cleaned up more FindArg's - Sound Options arch/sdl/gr.c, arch/ogl/gr.c, include/args.h, main/automap.c, main/automap.h, main/collide.c, main/collide.h, main/game.c, main/gamefont.c, main/gauges.c, main/gauges.h, main/hud.c, main/inferno.c, main/kconfig.c, main/netlist.c, main/newmenu.c, main/powerup.c, main/scores.c, main/weapon.c: Cleaned up more FindArg's - Graphics Options 20070714 -------- SConstruct, main/game.c, main/inferno.c: removed old CD-Play code SConstruct, d1x.ini, arch/sdl/init.c, arch/sdl/joy.c, include/args.h, main/args.c, main/config.c, main/game.c, main/game.h, main/gauges.c, main/hud.c, main/inferno.c, main/kconfig.c, main/kmatrix.c, main/laser.c, main/menu.c, main/multi.c, main/newdemo.c, main/newdemo.h, main/piggy.c, main/titles.c: Placing FindArg calls to seperated function, putting variables to a struct - frist step, not finished, yet; Large code cleanup 20070629 -------- main/playsave.c, main/titles.c: fixing playerfile size detection, using gr_flip() with title screens 20070628 -------- main/game.c, main/newdemo.c: fixing compiler warning, handle *SOUND_TO_OBJ events correctly in demo playback 20070616 -------- main/newmenu.c: adjusted size of Inputbox 20070615 -------- SConstruct, arch/sdl/digi.c: complete removal of hmiplay-code usage main/text.c: fixed memleak 2d/bitblt.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, main/game.c, main/newmenu.c: small code cleanup; improved texture caching in menus to save RAM 20070614 -------- main/polyobj.c, main/render.c: using size_t when it comes to integer to pointer conversions d1x.ini, main/game.c, main/gauges.c, main/hud.c, main/inferno.c, main/kconfig.c, main/menu.c, main/playsave.c, main/radar.c: fixed axis direction for vertical and sideways thrust time; fixed y-Offset for mouse selection in kconfig_sub; removed (useless) Shrink/Grow window feature to clean code a bit; saving Cockpit mode in PLX file; improved grabmouse so mouse is always released in non-SCREEN_GAME modes 20070611 -------- SConstruct, 2d/font.c, arch/linux/hmiplay.c, arch/linux/init.c, arch/linux/ipx_bsd.c, arch/linux/ukali.c, arch/win32/init.c, include/ipx_drv.h, main/fvi.c, main/inferno.c, main/ipx_drv.c, main/gameseq.c, main/m_inspak.c, main/multibot.c, main/multi.c, main/multi.h, main/multiver.c, main/netpkt.h, main/newmenu.c, main/nncoms.c, main/render.c, main/state.c: fixed a bunch of compiler warnings SConstruct, arch/sdl/mouse.c, arch/sdl/include/mouse.h, arch/win32/include/mouse.h, arch/ogl/gr.c, editor/ksegsize.c, editor/segment.c, editor/seguvs.c, ui/mouse.c, include/types.h, main/gamesave.c, main/netlist.c, main/network.c, main/newdemo.c: fixed more compiler warnings 20070610 -------- 2d/bitblt.c, 2d/font.c, 2/rle.c, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, include/gr.h, include/rle.h, main/game.c, main/gauges.c, main/titles.c: introduced new bitmap flag to draw cockpit bitmap with transparency; draw transparent cockpit bitmap over gauges to make it more pixel-correct; code cleanups 20070601 -------- main/menu.c, main/netlist.c, main/network.c, main/newmenu.c: improved pixel-correct (almost) scaling of menus; new Netgame info screen which can show up necessary game rules 20070530 -------- SConstruct, arch/ogl/gr.c, ui/window.c: Added conditions to add compiler/linker flags from user's environemnt if they have any set; make sure gl functions are not called before OpenGL is initialised, when fullscreen switching; use new 3 argument mouse_get_delta to avoid compiler errors 20070516 -------- main/game.c, main/inferno.c, main/newmenu.c: free grabbed mouse in Demo Playback; improved Player-files deletion 20070514 -------- SConstruct, arch/sdl/init.c, arch/sdl/joydefs.c, arch/sdl/mouse.c, arch/sdl/include/mouse.h, main/game.c, main/inferno.c, main/kconfig.c, main/kconfig.h, main/newmenu.c, main/newmenu.h, main/playsave.c, main/text.h: Added config field to map a Mouse Axis/Wheel to cycle Primary and Secondary weapons; lots of controls-related code cleaning main/laser.c: fixed speeding bug in homing system main/game.c: make sure Game_window_w/h is always set to a valid value in every cockpit mode 20070510 -------- main/inferno.c: read -pilot arg with and without filename extension 20070509 -------- arch/ogl/gr.c, arch/sdl/gr.c, main/game.c, main/newmenu.c: update viewing values at Fullscreen Toggle; added Fullscreen Toggle to Menus and Demo Playback 20070503 -------- CHANGELOG.txt, COPYING.txt, INSTALL.txt, README.txt: updated docs SConstruct: Version-Tag 0.52 20070502 -------- main/game.c, main/gauges.c: resolved some overlapping HUD elements main/args.c: improved INI-File parsing main/game.c: rev432 revisited - do not send multi De-Cloak packet in Demo Playback 20070421 -------- main/hud.c: prevent string placeholders in HUD Messages which may crash the game 20070420 -------- main/laser.c: made smart blobs easier to dodge main/kconfig.c: increased offset to detect movement on Joystick axis for mapping function 20070415 -------- main/multi.c: forbid % to read into multi messages to not mess up the string 20070414 -------- main/kconfig.c, main/kmatrix.c, main/newmenu.c, main/scores.c, main/titles.c: introducing kconfig_sub_draw_table() making it possible to redraw configuration tables with OGL swapping and clearing; increased timer_delay for menus and briefings to save more CPU usage 20070412 -------- main/game.c, main/gameseq.c, main/reorder.c: removed some code from Weapon Ordering which broke primary cycling main/game.c: introduced do_weapon_stuff() to abstract code from ReadControls() 20070407 -------- main/newmenu.c: hide cursor after newmenu_get_filename() 20070406 -------- SConstruct: some help correction 20070405 -------- main/game.c, main/game.h, main/gameseq.c, main/gauges.c, main/inferno.c, main/menu.c, main/playsave.c: remove final remains of VR_current_page and VR_use_paging, resolution variable cleanup - remove VR_screen_mode and VR_render_width/height (Game_screen_mode is the actual resolution put in an int, not an index) SConstruct: BINARY_SUBDIR should be bin/, not games/ 20070404 -------- main/newdemo.c, main/newmenu.c: clear HUD-Messages if a Demo starts so old messages do not appear; also set gr_palette_load() in nm_draw_background1 so palette resets if Demo-playback is cancelled d1x.ini, main/inferno.c, main/menu.c, main/newdemo.c: improved Autodemo-feature - less code, activate AFTER pilot is selected to make sure resolution and player-file operations do not mess up main/inferno.c, main/game.c: compile-time fix for demo stuff; close menu with boxed message 20070401 -------- main/newmenu.c: moved gr_palette_load() in nm_draw_background so it always does apply and resets step-ups properly main/game.h, main/gauges.c, main/menu.c: remove 'extern int last_drawn_cockpit[2]' since it's now a single int (not an array), fixing memory corruption (whoops!!) main/automap.c: merge and move automap border drawing code to draw_automap, so it could be used to draw the automap again just before showing a dialog box 20070331 -------- main/menu.c: improved Error-handling for loading missions d1x.ini, main/game.c, main/inferno.c: a switch to disable timer_delay in calc_frame_time - may be used if game runs a bit choppy 20070330 -------- main/game.c, main/newmenu.c, main/newmenu.h: introduced newmenu_dotiny() from D2X to show menus with GAME_FONT; extended Help-menu and removed D1X-Help-menu cfile/cfile.c: Error-proof cfile_init_hogfile() main/game.c, main/newdemo.c: dropped Newdemo Un/pause feature - unreliable, creates corrupt data 20070329 -------- main/automap.c, main/game.c, main/newmenu.c: palette-related fixes for Doublebuffered menus; fixes for SDL-build 20070326 -------- main/game.c, main/menu.c: unbind Minus/Equal from Shrink/Grow-window - only use ALT-F9/F10 to get richt with all keyboard layouts; Always allow screen resolution switching, even if selected is not supported to ensure Multi-Monitor support main/game.c, main/gauges.c, main/hud.c, main/inferno.c, main/newmenu.c, main/screens.h: draw mine view directly to screen with SDL Video, no using an offscreen buffer (will use SDL_Flip later) 20070325 -------- cfile/cfile.c, main/titles.c: fixed possible corrpution with nfiles cin cfile_init_hogfile; improved briefing delay usage SConstruct, arch/linux/init.c, arch/sdl/key.c, arch/sdl/timer.c, arch/win32/init.c, include/timer.h, main/automap.c, main/game.c, main/inferno.c, main/kconfig.c, main/kmatrix.c, main/menu.c, main/multi.c, main/newmenu.c, main/scores.c, main/titles.c: removed d_delay, now using timer_delay as wrapper for SDL_Delay 20070322 -------- SConstruct, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, main/credits.c, main/game.c, main/kconfig.c, main/kmatrix.c, main/menu.c, main/netlist.c, main/newmenu.c, main.polyobj.c, main/scores.c, main/state.c, main/titles.c: Use Doublebuffer in OGL for all parts of the game and properly redraw elements, fixed Profiler build 2d/canvas.c, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, arch/sdl/gr.c, arch/win32/gr.c, include/gr.h, main/automap.c, main/credits.c, main/inferno.c, main/game.c, main/game.h, main/gauges.c, main/hud.c, main/kconfig.c, main/kmatrix.c, main/netlist.c, main/newmenu.c, main/scores.c, main/titles.c: add gr_flip, allowing significant cleanup; remove final remnants of VR_current_page, also allowing -nodoublebuffer switch for all platforms 20070318 -------- SConstruct, main/game.c: fixed compiling without jukebox code if no SDL_mixer available arch/sdl/jukebox.c, arch/sdl/mixdigi.c, arch/sdl/mixmusic.c: slight music management improvements d1x.ini: typo fixed, sdl_mixer-related options added 20070312 -------- misc/dl_list.c, include/dl_list.h: doubly-linked list implementation main/game.c, arch/sdl/jukebox.c, arch/sdl/include/jukebox.h, arch/sdl/mixdigi.c, arch/sdl/include/mixdigi.h, SConstruct: new in-game jukebox system 20070306 -------- main/kconfig.c, main/kconfig.h, main/newmenu.c, main/playsave.c, main/scores.c: implemented expanded Joystick configuration panel (Thanks xatmes); corrected draw functions for kconfig_sub() and Scoreboard to show them correct in non 4/3 aspects; corrected Close-boxes for Mouse Menu control 20070304 -------- main/menu.c: improved Error-handling for starting a mission, making the game not crash if Level file is not found main/guages.c: cleaned up hud_show_weapons_mode() SConstruct, main/hud.c, main/hudlog.c: removed WANT_AWE32 flag - too buggy; scaled space between Hud-messages; block Hudlog output messages beginning with you (your ... maxed out, you already have ...) 20070303 -------- main/game.c, main/newmenu.c: some menu fixes 20070228 -------- main/game.c: newdemo-related fixes 20070226 -------- arch/ogl/ogl.c, main/endlevel.c, main/object.c: improved DepthTest, fixing Clipping bugs main/game.c: reset GameTime properly if needed 20070220 -------- arch/sdl/key.c: Added ENTER as Game key texmap/scanline.c: removed unreliable gr_fade_table check in c_tmap_scanline_per() arch/ogl/ogl.c, main/radar.c: don't show Radar box-fading in SDL; fixed OGL gr_ucircle() 20070219 -------- main/network.c, main/network.h: fixed player restriction at robot-/coop-games - code cleanup main/hudlog.c: block "You already have"-messages in HudLog output arch/ogl/ogl.c, main/game.c: removed BADTEXTURE cheat main/game.c: seperated Controls-reading functions in HandleEndlevelKey, HandleEndlevelKey, FinalCheatsKey, HandleGamekey; improved Game-key handling if Player_is_dead main/inferno.c, main/newdemo.c: fixed memory corruption in Demo-Playback main/hud.c: make 'Press any key ...'- and 'Demo recording' messages not overlap 20070218 -------- cfile/cfile.c: added patch by The_Lion to improve file handling with AltHogDir 20070217 -------- d1x.ini, main/inferno.c, main/laser.c: added Alex' patch to add FPS independent and physics homing missiles - also implemented command-line to switch back to legacy homers 20070214 -------- Makefile, SConstruct, arch/sdl/mixmusic.c, main/vers_id.h: Turning off sound debug flags; Optional micro versions (see SConstruct); Makefile emulation for SCons 20070211 -------- d1x.ini, main/collide.c, main/collide.h, main/fireball.c, main/inferno.c, main/object.c: improved debris random stuff, added -persistentdebris feature 20070209 -------- d1x.ini, main/inferno.c: added -gl_voodoo to OpenGL command-line switches and INI SConstruct: added default lflag path for *NIX build 20070208 -------- main/gauges.c: created offset for LOCK message string if demo record or playback 20070207 -------- main/game.c: expanded help menu and fixed d1x help iff/iff.c: amd64 fixes, code cleanup arch/linux/arch_ip.cpp, arch/linux/ipx_udp.c, arch/win32/arch_ip.cpp, main/ipclient.h: on-screen network error messages main/game.c: introducing HandleDeathKey - allows sending multi messages and options menu while dead 20070206 -------- main/inferno.c, main/menu.c, main/newdemo.c: fixed -demo and -autodemo switches to work with DEMO_DIR main/newmenu.c: use remove instead of unlink to delete plx-file safely 2d/bitblt.c, include/gr.h, main/automap.c, main/credits.c, main/titles.c: force show_fullscreen to software drawing if image is bigger than screen, showing Automap background in low resolutions via software, removed obsolete robot briefing fix in OGL, code cleanup 20070202 -------- arch/ogl/ogl.c: let ogl_ubitblt not return alpha channel to ogl_ubitblt_i arch/ogl/ogl.c: don't draw bombs with transparency even if -gl_transparency is enabled 20070130 -------- d1x.ini, arch/ogl/gr.c, arch/ogl/ogl.c, include/3d.h, main/inferno.c, main/object.c: added transparency effects for some bitmaps like explosions, powerups, weapons, etc. - to enable with -gl_transparency arch/linux/ipx_udp.c, main/ipclient.h: corrected UDP/IP error output dxx-readme.txt, SConstruct: preparations for v0.51 release 20070128 -------- main/radar.c: corrected radar positions and gave it a grey background so it's better visible 20070127 -------- main/credits: use ogl_ubitmapm_cs instead of show_fullscr in OGL to render faster main/game.c: corrected position of multi-message entry string 20070126 -------- main/credits.c: improved credits scrolling - not that smooth anymore, but less CPU intense d1x.ini, main/inferno.c: re-added -hudlines and -msgcolorlevel main/newmenu.c: scale menus properly when dealing with hiresfont dxx-readme.txt, dxx-compile.txt: improvements on dxx-readme's 20070125 -------- d1x.ini, arch/ogl.gr.c, cfile/cfile.c: include/gr.h, main/game.c, main/gamefont.c, main/inferno.c, main/menu.c, main/ndewdemo.c, main/newdemo.h, main/newmenu.c, titles.c: read/save Hires fonts/briefings, demos, AddOn missions, screenshots from/to subdirectories main/inferno.c: improved resolution-check method - removed old code texmap/scanline.c: fixed c-texmap transparency main/gauges.c: don't display lives and score if hud message is longer than 40 chars. preventing overlay of message and lives/score 20070122 -------- SConstruct, cfile/cfile.c: special WINDOWS fixes and cleanups arch/sdl/include/key.h: fixed PRINTSCREEN key for WINDOWS main/network.c: fixed multi summary reactor lifetime refresh 20070121 -------- main/gamesave.c, ui/mouse.c, ui/popup.c, ui/window.c: fixed EDITOR build d1x.ini, main/inferno.c: re-added missing command-line switches for SUPPORTS_NET_IP 20070120 -------- main/automap.c: for OGL don't display background bitmap if screen height < 400 because it won't fit - just draw grey main/render.c: removed inaccurate 4D hack, use GL_ALWAYS for special segments in level 19 only main/network.c: made short packets default on. long packets are still available but in general cause more problems than short arch/ogl/ogl.c: in g3_draw_sphere align rad according to canvas so it is always in round shape 20070119 -------- cfile/cfile.c: patch by TheLion: cfile_get_filehandle reads case-insensitive on *NIX systems - makes use of .rdl levels easier d1x.ini, main/inferno.c, main/hudlog.c, main/hudlog.h: tell user where descent.hog/pig should be if it isn't there, removed broken -hudlogdir code arch/ogl/gr.c: gr_upixelc now able to scale pixels to current resolution 20070118 -------- main/kconfig.c: prevent changing weapons if automap is active main/inferno.c, main/gameseq.c: only read and write lowercase pilots - prevents mistakes in -pilot option as well as multisaves 20070117 -------- main/endlevel.c: draw spheres instead of pixels in draw_stars to show correctly in OGL 20070113 -------- main/game.c: fixed key combo to shrink/grow window (lost while porting to GP2X) main/laser.c: limit homing missle turn-rate 20070110 -------- main/kconfig.c, main/newmenu.c, main/playsave.c: joystick axes can be reassigned; higher offset for axes moving detection; correction for menus that are bigger than screen; plxver correction (is actually used) 20070113 -------- main/object.c: removing the !dead statement (leftover from WraithX Deathcam) from object_move_one() so the function will return correctly if player dies instead running further and creating invalid code and crashes 20070112 -------- SConstruct: cleanup 20070109 -------- dxx-changelog.txt, arch/ogl/gr.c, arch/ogl/ogl.c, arch/ogl/include/ogl_init.h, main/playsave.c, texmap/scanline.c, texmap/tmapflat.c: allocate 'pixels' and 'texbuf' according to current screen resolution, saving over a hundred megabytes of memory; divide negative light rates of change properly (fix bug #2575) (from D2X CVS); divide negative window x-coordinates properly, fixing random crashes (from D2X CVS); make sscanf look for "%i.%i" instead of "v%i.%i" because the 'v' isn't written to file; added missing changelog entries 20061212 -------- arch/sdl/mixdigi.c, main/inferno.c: music volume now properly restored and remembered in D1 and D2, using a static int; removed ugly hack that fixed this bug in D1 (inferno.c, revision 230) 20061128 -------- 2d/bitmap.c, 2d/font.c, 2d/rle.c, SConstruct, include/gr.h, include/u_mem.h, main/config.c, main/game.c, main/newdemo.c, main/newmenu.c, main/text.c, maths/fixc.c, texmap/scanline.c: code optimisation and fixed mem-leaks 20061125 -------- gp2x/buttonmap.txt, gp2x/dxx-rebirth_buttonmap.pdf, gp2x/notes.txt, main/kconfig.c: optimized movements for GP2X; formatted and optimized GP2X readme's 20061122 -------- main/gauges.c: fixing small cockpit glitch in SDL mode 3d/interp.c, SConstruct, arch/sdl/clipboard.c, arch/sdl/digi.c, arch/sdl/event.c, arch/sdl/gr.c, arch/sdl/include/gp2x.h, arch/sdl/joy.c, arch/sdl/key.c, gp2x/buttonmap.txt, gp2x/dxx-rebirth_buttonmap.pdf, gp2x/notes.txt, main/bm.c, main/clock.c, main/config.c, main/game.c, main/inferno.c, main/kconfig.c, main/loadrl2.c, main/menu.c, main/newmenu.c, main/object.h, main/physics.c, main/polyobj.c, main/polyobj.h, main/scores.c, texmap/scanline.c: ARM CPU support with words alignment and GP2X handheld support 20061121 -------- mem/mem.c: correct casting in mem_check_integrity 20061117 -------- SConstruct, arch/sdl/include/key.h, arch/sdl/include/key_arch.h, arch/sdl/key.c, arch/sdl/key_arch.c, include/key.h, main/game.c, main/key.c: merged SDL keyboard functions from D2X 20061115 -------- main/automap.c: fixed missing automap side colors; re-added lost cheat; cleaned code to avoid warnings d1x.ini, main/inferno.c: corrected typo 20061102 -------- arch/sdl/include/joy.h, arch/sdl/joy.c, arch/win32/include/joy.h: improved joystick code for more buttons arch/ogl/gr.c, arch/ogl/include/ogl_init.h, d1x.ini, main/gauges.c, main/inferno.c: command-line to set glScissor off if needed 20061031 -------- main/kconfig.c: make sliding use sensitivity main/args.c, main/game.c, main/inferno.c: moved some FindArgs to main() so they are not called in the game; added printf for DEBUG to track FindArgs 20061029 -------- main/render.c: turning detriangulation off by default; not really needed anymore and makes rendering nicer 20061027 -------- arch/sdl/mixdigi.c: Another fix for crash on -nosound 20061024 -------- arch/sdl/mixdigi.c: Fix for crash with -nosound and looped sound volume adjustment 20061023 -------- /main/titles.c: moved gr_clear_canvas from show_briefing_screens to do_briefing_screens to avoid white blending /main/polyobj.c: using ogl_start/end_frame, instead of offscreen in draw_model_picture /arch/linux/hmiplay.c: added cut_trough(), a clone of stop_all that is called to flush notes while playing a song to improve song switching; added rephmi integer to see if song should repeat, acts together with a check of csec to send send_ip("s") if endlevel song is finished /arch/ogl/sdlgl.c, /arch/ogl/ogl.c, /main/endlevel.c: added GL functions, changed g3_draw_poly in d2x style to fix the portal-bug; added exception boolean value tempNoDepthTest to render endlevel correctly; code reformatting /arch/win32/hmpfile.c, /main/songs.c: code cleanups /arch/ogl/gr.c, /arch/sdl/gr.c, /main/inferno.c, /d1x.ini: added variable aspect function, changed cmd-help, changed ini file /arch/win32/digi.c: restored max_distance multiplication; using 0 instead of MIN_VOLUME to fix loud sound on fade-in functions /2d/bitblt.c, /arch/ogl/include/ogl_init.h, /arch/ogl/ogl.c, /main/titles.c: added bool transp to ogl_filltexbuf and following functions to show bitmaps without transparent pixels if returning 0. fixes unwanted transparency in briefing images; removed "gr_clear_canvas" in titles.c which was used as workaround for this bug /arch/ogl/ogl.c, /main/endlevel.c, /main/gameseg.c, /main/render.c: improved use of Depth Test, added experimental hack for 4D levels; removed two Asserts which fail with 4D levels /main/game.c: added game_flush_input() on automap calls to avaoid control irritations /main/inferno.c: corrected command-line output in inferno.c /dxx-readme.txt: corrected typo /arch/ogl/ogl.c: disabled GL_CULL_FACE at ogl_end_frame to avoid problems with menus after player's death /main/kconfig.c: correctly restoring backgrounds in control menus /main/gameseq.c, /main/hud.c: showing game over in d2x-way /main/newmenu.c, /main/newmenu.c: layed out special chars to newmenu.h, fixed menu bevels for OGL, fixed text position for scalable menus, code reformatting /main/gameseg.c: disabled another Assert. commented with FIXME's - debugging if needed /SConstruct, /arch/linux/joydefs.c, /arch/linux/joystick.c, /arch/linux/makefile, /arch/ogl/wgl.c, /arch/sdl/event.c, /arch/sdl/include/joy.h, /arch/sdl/joy.c, /arch/sdl/joydefs.c, /arch/sdl/makefile, /arch/win32/init.c, /arch/win32/midi.c, /dxx-compile.txt, /dxx-readme.txt, /editor/curves.c, /editor/group.c, /editor/makefile, /main/kconfig.c, /main/menu.c, /main/playsave.c, /ui/menubar.c, /ui/userbox.c: building with more SDL code, added lots of D2X SDL related code, windows build does not need DirectX anymore; implemented SCons build system; provisoric hacks to build editor; changed contents of readme and compile text files /SConstruct, /main/inferno.c: made windows build always pipe to stdout.txt and stderr.txt /d1x.ini, /main/inferno.c, /main/hudlog.c, /main/hudlog.h: hudlogstdout as default /arch/ogl/sdlgl.c: ogl_smash_texture_list_internal() should applay on windows in window mode as well to prevent texture problems /d1x.ini, /main/inferno.c, /main/game.c: changed mousegrab calls because of new use in windows as well /Sconstruct: added profiler support to SConstruct and merged debug and no_release /main/game.c: removed unwanted stop_time() in set_screen_mode(), that broke pause states and control stuff /arch/ogl/ogl.c, /main/automap.c: automap code from d2x, show borders in SDL and OGL, optimized and cleaned /2d/font.c, /arch/ogl/include/ogl_init.h, /arch/ogl/ogl.c, /d1x.ini, /include/gr.h, /main/automap.c, /main/game.c, /main/gamefont.c, /main/inferno.c, /main/kconfig.c, /main/menu.c, /main/newmenu.c, /main/scores.c, /main/state.c, /main/titles.c: made fonts scalable, added command-line to enable fixed fonts, added command-line to enable hires fonts, made savegame thumbs scalable, reworked menu borders, new way to display level info in automap to get right with scaled fonts /arch/ogl/ogl.c, /main/credits.c, /main/polyobj.c, /main/titles.c: new code for ogl_offscreen_render, used it to reduce flickering in credits and spinning robots, improved way to regognize hires briefing images /arch/ogl/gr.c, /arch/sdl/gr.c, /d1x.ini, /include/args.h, /main/args.c, /main/automap.c, /main/game.c, /main/gameseq.c, /main/inferno.c, /main/kconfig.c, /main/menu.c, /main/newmenu.c, /main/playsave.c, /main/scores.c: some fixes for menus and automap; new aspect code; improved code to scale window for cockpits; introducing new variable in playsave.c to store game resolution and saving Game_window_h/h again properly - fixes bugs with screwed resolutions; making menus in game-resolution as default and re-activating old command-line arg '-menux' to scale menus /arch/ogl/gr.c, /arch/ogl/ogl.c, /main/automap.c, /main/game.c, /main/gauges.c, /main/newmenu.c, /main/radar.c, /main/weapon.c: adjusted position of strings in hud and cockpit; made fadings work in OGL; made radar scale in cockpit mode; mede normal reticle default again and scaled it to current resolution for OGL; reformatted code to make it A BIT MORE readable /main/kconfig.c: corrected mouseaxis_text /texmap/ntmap.c increased MAX_Y_POINTERS to allow higher resolutions in SDL /main/game.c, /main/gauges.c: corrections and improvements for scalable HUD and cockpits, cleaner code, fixes to get SDL renderer working again /arch/sdl/joy.c, /arch/sdl/joydefs.c, /main/menu.c: fixed joystick deadzone feature and moved it and sensitivity to controls sub-menu /arch/sdl/mouse.c, /main/kconfig.c, /main/newmenu.c, /main/newmenu.h: added mouse in menus /SConstruct, /main/config.c: added command-line arg for SCons to specify Sharepath. Save config files, players etc. in home directory. Patch by Hans de Goede - THANKS /main/slew.h: fix error when building editor with RELEASE (d2x-cvs takeover) /main/inferno.c, main/titles.c, main/titles.h: move order form showing to titles.c (d2x-cvs takeover) /main/ipclient.cpp, /main/menu.c, /main/multi.h, /main/network.c: re-implemented D1X ONLY GAME option to server menu and set it always true on UDP/IP to fix compability issues. making use of alloca instead of malloc in ipx_ip_SendPacket /main/inferno.c: getting rid of inferno sound hacks /SConstruct, /main/game.c, /main/game.h, /main/gauges.c, /main/inferno.c, /main/menu.c, /main/playsave.c, /main/state.c, /main/titles.c: removing unnecessary stuff from game_init_render_buffers; better resolution handling; making shareware version using registered save/restore features; storing resolution stuff in PLX file and making compability to other D1X versions; cleaning up the code a bit; implemented SHAREWARE build in SCons and some fixes for SHAREWARE build (Thanks to Hans de Goede) /main/game.c, /mem/mem.c: making sure canvas is free if a new buffer is created /2d/bitblt.c, /arch/win32/mouse.c, /editor/eglobal.c, /editor/fixseg.c, /editor/group.c, /editor/medwall.c, /editor/segment.c, /editor/seguvs.c, /editor/texture.c, /iff/iff.c, /include/editor/editor.h, /include/editor/medwall.h, /include/gr.h, /include/iff.h, /include/rpcndr.h, /include/types.h, /include/ui.h, /main/ai.c, /main/aipath.c, /main/aistruct.h, /main/bm.c, /main/bm.h, /main/bmread.c, /main/config.c, /main/credits.c, /main/custom.h, /main/dumpmine.c, /main/fireball.c, /main/fuelcen.c, /main/fuelcen.h, /main/game.c, /main/gamesave.c, /main/gameseg.c, /main/gameseg.h, /main/gauges.c, /main/kconfig.c, /main/laser.c, /main/lighting.c, /main/loadrdl.h, /main/loadrl2.c, /main/menu.c, /main/mglobal.c, /main/modem.c, /main/multi.c, /main/multi.h, /main/multibot.c, /main/netpkt.h, /main/network.c, /main/network.h, /main/newdemo.c, /main/newdemo.h, /main/object.h, /main/paging.c, /main/player.h, /main/render.c, /main/robot.h, /main/scores.c, /main/segment.h, /main/state.c, /main/switch.c, /main/switch.h, /main/titles.c, /main/wall.h, /main/weapon.c, /main/weapon.h, /ui/icon.c: change byte to sbyte /main/altsound.c: fixing crash when playing sounds in lowmem /SConstruct, /arch/sdl/digi.c, /main/digi.h, /main/inferno.c, /main/newdemo.c, /main/newdemo.h: implemented sound code of d2x /arch/sdl/joydefs.c, /main/gameseq.c, /main/kconfig.c, /main/kconfig.h, /main/newmenu.c, /main/playsave.c: added new control type: Joystick & Mouse (Thanks to The_Lion) /main/credits.c, /main/scores.c, /main/state.c, /main/titles.c: better handling for hires briefings; fixing some memleaks; code cleanup /2d/font.c, /arch/ogl/include/ogl_init.h, /arch/ogl/ogl.c, /main/automap.c, /main/game.c, /main/gauges.c, /main/state.c, /main/titles.c: corrected demo-related font positions; merged ogl_ubitmapm_cs and ogl_ubitmapm_cf /2d/font.c, /main/game.c, /main/inferno.c, /main/menu.c: cleaned up options menu and removed 'd1x options' because not really necessary anymore /arch/ogl/gr.c, /arch/sdl/gr.c: don't give GL extensions on release build, code cleanup /2d/font.c, /arch/ogl/gr.c, /include/ogl_init.h, /arch/ogl/sdlgl.c, /include/gr.h, /main/inferno.c: introduced FSAA; re-enabled fullscreen toggle in menus again and fixed glitches; adjusted OGL_TEXTURE_LIST_SIZE and OGLTEXBUFSIZE; code cleanup; restored font.c (oops) /arch/ogl/sdlgl.c, /arch/sdl/gr.c, /main/gameseq.c, /main/inferno.c, /main/newmenu.c,/main/vers_id.h: if player is deleted also delete PLX file; removed D1X_DATE, not necessary; corrected Menu_special /SConstruct: added install routine; preparations for v0.50 release /main/gauges.c: corrected position of shield/energy numbers if 200 /SConstruct, /arch/ogl/gr.c, /arch/ogl/include/ogl_init.h, /arch/ogl/ogl.c, /arch/ogl/sdlgl.c, /include/gr.h, /main/inferno.c: added SDL_SetGammaRamp; removed FSAA because no function on all platforms; fixed offscreen render; fixed sharepath in SConstruct /arch/sdl/joydefs.c, /main/newmenu.c: menu-related fixes /main/render.c, /main/wall.c: improved 4D room detection /main/newmenu.c: restore palette in menus for SDL_SetGammaRamp /main/gameseq.c: don't run joydefs_calibrate if joystick is not selected as input device /arch/ogl/gr.c: switching SDL gammaramp off by default because uses too much CPU /main/hud.c: aligned 'press any key...' message on hud /main/newmenu.c: added forgotten {} to count citem correctly and select last player again /main/credits.c: make scrolling smoother by changing time_delay /main/playsave.c: involve hli entry to determinate player_file_size correctly /main/game.c: corrected position of FPS counter /main/menu.c: print warning if resolution is set too high and don't change after all /main/inferno.c: using ReadConfigFile earlier to make it possible to read D1X.INI from home directory /main/radar.c: corrected radar y position /arch/sdl/joydefs.c: re-activated Weapon Keys menu - aka D1X keys /arch/ogl/gr.c, /arch/sdl/include/joy.h, /arch/sdl/joy.c, /main/inferno.c, /main/kconfig.c: improved SDL Joystick axes recognition; fixing mem corruptions while closing joysticks; removed Joystick calibration which should be unnecessary with SDL; fixing printf format in gr.c /arch/ogl/ogl.c: Fix for inherent limitation in pow2ize() and wrong description thereof /d1x.ini, /main/inferno.c, /main/multi.c: cleaned up command-line help; removed old/redundant/unfunctional options; improved code to read -pilot/-demo argument /arch/ogl/gr.c, /include/gr.h, /main/game.c, /main/netlist.c, /main/newmenu.c: removed fullscreen menu toggle - does not work on any arch and hasn't since we have toggle in resolution menu /arch/ogl/loadgl.h, /main/gauges.c: introducing draw_wbu_border to draw rounded weapon boxes with glScissor /main/game.c: removed calibrate joystick line from help menu /arch/ogl/ogl.c, /arch/ogl/include/ogl_init.h: made lines width scale to resolution; fixed compiler warnings /main/game.c: new handling for keys after player is exploded /main/inferno.c, /main/kconfig.c: using global variable for sp-mouselook to save CPU usage 20060416 -------- /main/credits.c: new credits code /arch/hmpfile.c, /main/songs.c: improved midi shutdown at end of game /main/game.c: shrink/grow window not correct with scalable cockpits /arch/ogl/ogl.c, /arch/ogl/include/ogl_init.h, /main/game.c, /main/gauges.c: scalable cockpits /main/gauges.c: FIX: if "you already have 20 concussion missles!" is displayed, lives and score disappeared /main/newdemo.c: FIX: demo recording crashed game at X demo size /arch/ogl/wgl.c: FIX: fan-crash bug /include/gr.h: deactivated possibility to switch window/fullscreen in menu /main/game.c: mouse capture deactivated in menus for linux /arch/win32/wgl.c: ALT-key does not call windows frame options anymore /main/physics.c: allow asserting objet to none if player is dead - fixes some random crashes /main/titles.c: fix to show white instead of black background for semi-transparent briefing bitmaps /main/newdemo.c: new interpolate function for demos; changed call for d_delay to nice demo playback /arch/sdl/gr.c, /arch/ogl/gr.c, /main/inferno.c: added widescreen aspect with command-line option for SDL and OGL build /main/newmenu.h: possible menu text sring length incrased to 255 /arch/ogl/gr.c, /main/menu.c: removed fullok hack for fullscreen changing /main/polyobj.c: using OGL offscreen render to reduce flickering in spinning briefing robots various: new build system 20060224 -------- /arch/ogl/include/ogl_init.h: fixing "OGL: texture list full"-bug /main/game.c, /main/gameseq.c: beter code older compilers (thanks to AD) /main/state.c: better savegame thumbs for every resolution /main/network.c, /main/multi.h, /main/menu.c: removed "D1X ONLY GAME" option, code cleaning /rules.mak, /main/vers_id.h: changes in date, version-number /main/gauges.c: fix for invulnerable/cloak hud font colors that had color of your last key /main/game.c: new keys to get shrink and grow window functions working /main/automap.c, /main/inferno.c: automap now always in gameres and eat less cpu power /main/kconfig.c: fix laser fire if energy and vulcan ammo recharged after 0 /main/gauges.c: fix weapons descriptions in cockpit mode /main/menu.c, /main/playsave.c: save function for resolutions /main/menu.c: custom resolutions support /main/game.c: smoother demo playback /arch/win32/digi.c, /arch/win32/hmpfile.c, /arch/win32/hmpfile.h, /arch/win32/hmiplay.c: fix for incorrect midi loops on windows /main/game.c: fix to shrink window correctly /main/credits.c: removed flickering and added fading to credits /arch/win32/makefile, /arch/win32/makefile.nt: removed d1x.rc and d1x_res.rc from compiiling so ALT key doesn't call frame options in window-mode on windows /arch/win32/digi.c: fix that fans not play in menus on windows systems 20060122 -------- /main/gauges.c: preventing vulcan ammo index overlapping reticle at high resolutions /main/ipclient.cpp: fixed segfault when starting udp/ip game /main/newmenu.c: comments an cleaning 20060116 -------- /main/states.c: fix for text position in save/load screen while using hires fonts /arch/ogl/gr.c: fix for screenshot function /main/inferno.c, /main/kconfig.c: new function for optional mouselook style feature /main/state.c: fix for broken savegames /main/credits.c: fix for credits background palette /main/gamefont.c: added optional hires fonts from D2 /main/gauges.c: new HUD icons for lives and keys if hires fonts /main/gameseq.c: fixed palette after endgame /main/titles.c: image fix while endgame in lowres briefings, implementation of hires briefings /arch/win32/digi.c: fix for fading/panning in windows /arch/ogl/gr.c, /main/game.c, /main/menu.c: fix for fullscreen switching in windows /arch/ogl/ogl.c, /main/inferno.c: implementation of trilinear filtering /main/mission.h: fix to hold up to 5000 addon levels /main/inferno.c, /main/game.c: grabmouse feature for linux /main/inferno.c: menus at 640x480 are standard now (fits better), fix for soundloops after game quit (some onboard soundcards) /main/game.c: made nicefps standard. better gameplay, lesser cpu usage, a little pause in linux for resolution change at new game /main/menu.c: resolutions up to 1600x1200 /arch/ogl/gr.c, /arch/sdl/gr.c, /main/inferno.c: made fullscreen standard, changed '-fullscreen' option to '-window' /arch/ogl/wgl.c: build fix /arch/ogl/gr.c: fix for ingame screenshots /main/args.c: fix for crashes while using modified d1x.ini various: code cleaning, fixes and additional includes for windows build, restructuration for new multiplatform release 20051025 -------- /main/state.c: fixed crash while loading saved game /main/polyobj.c: fixed slow spinning robots in briefing /main/titles.c: fixed exit-door in briefing /main/kconfig.c: much better mouse movement /main/vers_id.h: program and version specific changes /include/cfile.h: added definition for DESCENT_DATA_PATH d1x-install.sh: changes for v0.04 README.TXT: removed/changed some known issues added gentoo and suse 10 to working ditributions added Maystorm to Thanks section Changelog: file created 20050916 -------- initial release dxx-rebirth-0.58.1-d1x/COPYING.txt000066400000000000000000000037441217717257200164330ustar00rootroot00000000000000D1X-Rebirth License Preamble -------- This License is designed to allow the Descent programming community to continue to have the Descent source open and available to anyone. Original Parallax License ------------------------- THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. We make no warranties as to the usability or correctness of this code. ------------------------- The D1X-Rebirth project is the combination of the original Parallax code and the modifications and additions made to source code. While the original code is only under the Original Parallax License the D1X-Rebirth project contains original code that was not made by Parallax. This ADDED and/or CHANGED code has the following added restrictions: 1) By using this source you are agreeing to these terms. 2) D1X-Rebirth and derived works may only be modified if ONE of the following is done: a) The modified version is placed under this license. The source code used to create the modified version is freely and publicly available under this license. b) The modified version is only used by the developer. 3) D1X-REBIRTH IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. dxx-rebirth-0.58.1-d1x/D1X.make000066400000000000000000000333141217717257200160110ustar00rootroot00000000000000# File: D1X.make # Purpose: Compile d1x (descent 1 port to Unix) with MPW for Mac OS 9 # Target: D1X # Created: Saturday, June 12, 2004 04:38:06 PM MAKEFILE = D1X.make ¥MondoBuild¥ = #{MAKEFILE} Make blank to avoid rebuilds when makefile is modified ObjDir = ":obj:" Includes = ¶ -i :include: ¶ -i :arch:include: ¶ -i "{CIncludes}SDL:" ¶ -i :arch:carbon: ¶ -i "{CIncludes}" ¶ -i :main: Sym-PPC = -sym on PPCAOptions = {Includes} {Sym-PPC} # Comment out '-d OGL' to build for SDL Video # More to do further down where the PPCLink call is... PPCCOptions = {Includes} -includes unix -prefix conf.h {Sym-PPC} -d HAVE_CONFIG_H -enum int -noMapCR -w 2,7,30,35 -d OGL -d USE_SDLMIXER -d NDEBUG -d RELEASE ### Source Files ### SrcFiles = ¶ :2d:2dsline.c ¶ :2d:bitblt.c ¶ :2d:bitmap.c ¶ :2d:box.c ¶ :2d:canvas.c ¶ :2d:circle.c ¶ :2d:disc.c ¶ :2d:font.c ¶ :2d:gpixel.c ¶ :2d:line.c ¶ :2d:palette.c ¶ :2d:pcx.c ¶ :2d:pixel.c ¶ :2d:poly.c ¶ :2d:rect.c ¶ :2d:rle.c ¶ :2d:scalec.c ¶ :2d:tmerge.c ¶ :3d:clipper.c ¶ :3d:draw.c ¶ :3d:globvars.c ¶ :3d:instance.c ¶ :3d:interp.c ¶ :3d:matrix.c ¶ :3d:points.c ¶ :3d:rod.c ¶ :3d:setup.c ¶ :arch:carbon:SDL_main.c ¶ :arch:ogl:gr.c ¶ :arch:ogl:ogl.c ¶ :arch:sdl:digi.c ¶ :arch:sdl:digi_audio.c ¶ :arch:sdl:digi_mixer.c ¶ :arch:sdl:digi_mixer_music.c ¶ :arch:sdl:event.c ¶ :arch:sdl:gr.c ¶ :arch:sdl:init.c ¶ :arch:sdl:joy.c ¶ :arch:sdl:jukebox.c ¶ :arch:sdl:key.c ¶ :arch:sdl:mouse.c ¶ :arch:sdl:rbaudio.c ¶ :arch:sdl:timer.c ¶ :arch:sdl:window.c ¶ :iff:iff.c ¶ :main:ai.c ¶ :main:aipath.c ¶ :main:automap.c ¶ :main:bm.c ¶ :main:bmread.c ¶ :main:cntrlcen.c ¶ :main:collide.c ¶ :main:config.c ¶ :main:console.c ¶ :main:controls.c ¶ :main:credits.c ¶ :main:custom.c ¶ :main:digiobj.c ¶ :main:dumpmine.c ¶ :main:effects.c ¶ :main:endlevel.c ¶ :main:fireball.c ¶ :main:fuelcen.c ¶ :main:fvi.c ¶ :main:game.c ¶ :main:gamecntl.c ¶ :main:gamefont.c ¶ :main:gamemine.c ¶ :main:gamerend.c ¶ :main:gamesave.c ¶ :main:gameseg.c ¶ :main:gameseq.c ¶ :main:gauges.c ¶ :main:hash.c ¶ :main:hostage.c ¶ :main:hud.c ¶ :main:inferno.c ¶ :main:kconfig.c ¶ :main:kmatrix.c ¶ :main:laser.c ¶ :main:lighting.c ¶ :main:menu.c ¶ :main:mglobal.c ¶ :main:mission.c ¶ :main:morph.c ¶ :main:multi.c ¶ :main:multibot.c ¶ :main:net_ipx.c ¶ :main:net_udp.c ¶ :main:newdemo.c ¶ :main:newmenu.c ¶ :main:object.c ¶ :main:paging.c ¶ :main:physics.c ¶ :main:piggy.c ¶ :main:player.c ¶ :main:playsave.c ¶ :main:polyobj.c ¶ :main:powerup.c ¶ :main:render.c ¶ :main:robot.c ¶ :main:scores.c ¶ :main:slew.c ¶ :main:snddecom.c ¶ :main:songs.c ¶ :main:state.c ¶ :main:switch.c ¶ :main:terrain.c ¶ :main:texmerge.c ¶ :main:text.c ¶ :main:titles.c ¶ :main:vclip.c ¶ :main:wall.c ¶ :main:weapon.c ¶ :maths:fixc.c ¶ :maths:rand.c ¶ :maths:tables.c ¶ :maths:vecmat.c ¶ :mem:mem.c ¶ :misc:args.c ¶ :misc:dl_list.c ¶ :misc:error.c ¶ :misc:hmp.c ¶ :misc:ignorecase.c ¶ :misc:physfsx.c ¶ :misc:strio.c ¶ :misc:strutil.c ¶ :texmap:ntmap.c ¶ :texmap:scanline.c ¶ :texmap:tmapflat.c ¶ :texmap:tmapppc.a ### Object Files ### OpenGLObjects = ¶ "{ObjDir}gr.c.x" ¶ "{ObjDir}ogl.c.x" SDLVideoObjects = ¶ "{ObjDir}SDL:gr.c.x" GeneralObjects = ¶ {ObjDir}2dsline.c.x ¶ {ObjDir}bitblt.c.x ¶ {ObjDir}bitmap.c.x ¶ {ObjDir}box.c.x ¶ {ObjDir}canvas.c.x ¶ {ObjDir}circle.c.x ¶ {ObjDir}disc.c.x ¶ {ObjDir}font.c.x ¶ {ObjDir}gpixel.c.x ¶ {ObjDir}line.c.x ¶ {ObjDir}palette.c.x ¶ {ObjDir}pcx.c.x ¶ {ObjDir}pixel.c.x ¶ {ObjDir}poly.c.x ¶ {ObjDir}rect.c.x ¶ {ObjDir}rle.c.x ¶ {ObjDir}scalec.c.x ¶ {ObjDir}tmerge.c.x ¶ {ObjDir}clipper.c.x ¶ {ObjDir}draw.c.x ¶ {ObjDir}globvars.c.x ¶ {ObjDir}instance.c.x ¶ {ObjDir}interp.c.x ¶ {ObjDir}matrix.c.x ¶ {ObjDir}points.c.x ¶ {ObjDir}rod.c.x ¶ {ObjDir}setup.c.x ¶ {ObjDir}SDL_main.c.x ¶ {ObjDir}digi.c.x ¶ {ObjDir}digi_audio.c.x ¶ {ObjDir}digi_mixer.c.x ¶ {ObjDir}digi_mixer_music.c.x ¶ {ObjDir}event.c.x ¶ {ObjDir}init.c.x ¶ {ObjDir}joy.c.x ¶ {ObjDir}jukebox.c.x ¶ {ObjDir}key.c.x ¶ {ObjDir}mouse.c.x ¶ {ObjDir}rbaudio.c.x ¶ {ObjDir}timer.c.x ¶ {ObjDir}window.c.x ¶ {ObjDir}iff.c.x ¶ {ObjDir}ai.c.x ¶ {ObjDir}aipath.c.x ¶ {ObjDir}automap.c.x ¶ {ObjDir}bm.c.x ¶ {ObjDir}bmread.c.x ¶ {ObjDir}cntrlcen.c.x ¶ {ObjDir}collide.c.x ¶ {ObjDir}config.c.x ¶ {ObjDir}console.c.x ¶ {ObjDir}controls.c.x ¶ {ObjDir}credits.c.x ¶ {ObjDir}custom.c.x ¶ {ObjDir}digiobj.c.x ¶ {ObjDir}dumpmine.c.x ¶ {ObjDir}effects.c.x ¶ {ObjDir}endlevel.c.x ¶ {ObjDir}fireball.c.x ¶ {ObjDir}fuelcen.c.x ¶ {ObjDir}fvi.c.x ¶ {ObjDir}game.c.x ¶ {ObjDir}gamecntl.c.x ¶ {ObjDir}gamefont.c.x ¶ {ObjDir}gamemine.c.x ¶ {ObjDir}gamerend.c.x ¶ {ObjDir}gamesave.c.x ¶ {ObjDir}gameseg.c.x ¶ {ObjDir}gameseq.c.x ¶ {ObjDir}gauges.c.x ¶ {ObjDir}hash.c.x ¶ {ObjDir}hostage.c.x ¶ {ObjDir}hud.c.x ¶ {ObjDir}inferno.c.x ¶ {ObjDir}kconfig.c.x ¶ {ObjDir}kmatrix.c.x ¶ {ObjDir}laser.c.x ¶ {ObjDir}lighting.c.x ¶ {ObjDir}menu.c.x ¶ {ObjDir}mglobal.c.x ¶ {ObjDir}mission.c.x ¶ {ObjDir}morph.c.x ¶ # {ObjDir}multi.c.x ¶ # {ObjDir}multibot.c.x ¶ {ObjDir}net_ipx.c.x ¶ {ObjDir}net_udp.c.x ¶ {ObjDir}newdemo.c.x ¶ {ObjDir}newmenu.c.x ¶ {ObjDir}object.c.x ¶ {ObjDir}paging.c.x ¶ {ObjDir}physics.c.x ¶ {ObjDir}piggy.c.x ¶ {ObjDir}player.c.x ¶ {ObjDir}playsave.c.x ¶ {ObjDir}polyobj.c.x ¶ {ObjDir}powerup.c.x ¶ {ObjDir}render.c.x ¶ {ObjDir}robot.c.x ¶ {ObjDir}scores.c.x ¶ {ObjDir}slew.c.x ¶ {ObjDir}snddecom.c.x ¶ {ObjDir}songs.c.x ¶ {ObjDir}state.c.x ¶ {ObjDir}switch.c.x ¶ {ObjDir}terrain.c.x ¶ {ObjDir}texmerge.c.x ¶ {ObjDir}text.c.x ¶ {ObjDir}titles.c.x ¶ {ObjDir}vclip.c.x ¶ {ObjDir}wall.c.x ¶ {ObjDir}weapon.c.x ¶ {ObjDir}fixc.c.x ¶ {ObjDir}rand.c.x ¶ {ObjDir}tables.c.x ¶ {ObjDir}vecmat.c.x ¶ {ObjDir}mem.c.x ¶ {ObjDir}args.c.x ¶ {ObjDir}dl_list.c.x ¶ {ObjDir}error.c.x ¶ {ObjDir}hmp.c.x ¶ {ObjDir}ignorecase.c.x ¶ {ObjDir}physfsx.c.x ¶ {ObjDir}strio.c.x ¶ {ObjDir}strutil.c.x ¶ {ObjDir}ntmap.c.x ¶ {ObjDir}scanline.c.x ¶ {ObjDir}tmapflat.c.x ¶ {ObjDir}tmapppc.a.x ### Libraries ### GeneralLibFiles = ¶ "{SharedLibraries}PhysicsFS" ¶ "{SharedLibraries}SDL" ¶ "{SharedLibraries}SDL_mixer" ¶ "{SharedLibraries}StdCLib" ¶ # "{SharedLibraries}CarbonLib" ¶ "{SharedLibraries}DialogsLib" ¶ "{SharedLibraries}InterfaceLib" ¶ "{SharedLibraries}MathLib" ¶ "{PPCLibraries}StdCRuntime.o" ¶ "{PPCLibraries}PPCCRuntime.o" ¶ "{PPCLibraries}PPCToolLibs.o" OpenGLFiles = ¶ "{SharedLibraries}OpenGLLibraryStub" ¶ "{SharedLibraries}OpenGLUtilityStub" ### Default Rules ### .a.x Ä .a {¥MondoBuild¥} {PPCAsm} {depDir}{default}.a -o {targDir}{default}.a.x {PPCAOptions} .c.x Ä .c {¥MondoBuild¥} {PPCC} {depDir}{default}.c -o {targDir}{default}.c.x {PPCCOptions} ### Build Rules ### # Comment out OpenGLObjects and OpenGLFiles for SDL Video build, commment out SDLVideoObjects for OpenGL build # This should be done for the following line as well as the arguments to PPCLink D1X ÄÄ directories {GeneralObjects} {GeneralLibFiles} {¥MondoBuild¥} {OpenGLObjects} {OpenGLFiles} #{SDLVideoObjects} PPCLink ¶ -o {Targ} ¶ {GeneralObjects} ¶ # {SDLVideoObjects} ¶ {OpenGLObjects} ¶ {GeneralLibFiles} ¶ {OpenGLFiles} ¶ {Sym-PPC} ¶ -mf -d ¶ -m main ¶ -t 'APPL' ¶ -c 'DCNT' Rez -a -o {Targ} ":arch:carbon:descent.r" # This is used to create the directories needed for build directories Ä if !`Exists obj` ; NewFolder obj ; end if !`Exists :obj:SDL` ; NewFolder :obj:SDL ; end ### Required Dependencies ### {ObjDir}2dsline.c.x Ä :2d:2dsline.c {ObjDir}bitblt.c.x Ä :2d:bitblt.c {ObjDir}bitmap.c.x Ä :2d:bitmap.c {ObjDir}box.c.x Ä :2d:box.c {ObjDir}canvas.c.x Ä :2d:canvas.c {ObjDir}circle.c.x Ä :2d:circle.c {ObjDir}disc.c.x Ä :2d:disc.c {ObjDir}font.c.x Ä :2d:font.c {ObjDir}gpixel.c.x Ä :2d:gpixel.c {ObjDir}line.c.x Ä :2d:line.c {ObjDir}palette.c.x Ä :2d:palette.c {ObjDir}pcx.c.x Ä :2d:pcx.c {ObjDir}pixel.c.x Ä :2d:pixel.c {ObjDir}poly.c.x Ä :2d:poly.c {ObjDir}rect.c.x Ä :2d:rect.c {ObjDir}rle.c.x Ä :2d:rle.c {ObjDir}scalec.c.x Ä :2d:scalec.c {ObjDir}tmerge.c.x Ä :2d:tmerge.c {ObjDir}clipper.c.x Ä :3d:clipper.c {ObjDir}draw.c.x Ä :3d:draw.c {ObjDir}globvars.c.x Ä :3d:globvars.c {ObjDir}instance.c.x Ä :3d:instance.c {ObjDir}interp.c.x Ä :3d:interp.c {ObjDir}matrix.c.x Ä :3d:matrix.c {ObjDir}points.c.x Ä :3d:points.c {ObjDir}rod.c.x Ä :3d:rod.c {ObjDir}setup.c.x Ä :3d:setup.c {ObjDir}SDL_main.c.x Ä :arch:carbon:SDL_main.c {ObjDir}gr.c.x Ä :arch:ogl:gr.c {ObjDir}ogl.c.x Ä :arch:ogl:ogl.c {ObjDir}digi.c.x Ä :arch:sdl:digi.c {ObjDir}digi_audio.c.x Ä :arch:sdl:digi_audio.c {ObjDir}digi_mixer.c.x Ä :arch:sdl:digi_mixer.c {ObjDir}digi_mixer_music.c.x Ä :arch:sdl:digi_mixer_music.c {ObjDir}event.c.x Ä :arch:sdl:event.c {ObjDir}SDL:gr.c.x Ä :arch:sdl:gr.c {ObjDir}init.c.x Ä :arch:sdl:init.c {ObjDir}joy.c.x Ä :arch:sdl:joy.c {ObjDir}jukebox.c.x Ä :arch:sdl:jukebox.c {ObjDir}key.c.x Ä :arch:sdl:key.c {ObjDir}mouse.c.x Ä :arch:sdl:mouse.c {ObjDir}rbaudio.c.x Ä :arch:sdl:rbaudio.c {ObjDir}timer.c.x Ä :arch:sdl:timer.c {ObjDir}window.c.x Ä :arch:sdl:window.c {ObjDir}iff.c.x Ä :iff:iff.c {ObjDir}ai.c.x Ä :main:ai.c {ObjDir}aipath.c.x Ä :main:aipath.c {ObjDir}automap.c.x Ä :main:automap.c {ObjDir}bm.c.x Ä :main:bm.c {ObjDir}bmread.c.x Ä :main:bmread.c {ObjDir}cntrlcen.c.x Ä :main:cntrlcen.c {ObjDir}collide.c.x Ä :main:collide.c {ObjDir}config.c.x Ä :main:config.c {ObjDir}console.c.x Ä :main:console.c {ObjDir}controls.c.x Ä :main:controls.c {ObjDir}credits.c.x Ä :main:credits.c {ObjDir}custom.c.x Ä :main:custom.c {ObjDir}digiobj.c.x Ä :main:digiobj.c {ObjDir}dumpmine.c.x Ä :main:dumpmine.c {ObjDir}effects.c.x Ä :main:effects.c {ObjDir}endlevel.c.x Ä :main:endlevel.c {ObjDir}fireball.c.x Ä :main:fireball.c {ObjDir}fuelcen.c.x Ä :main:fuelcen.c {ObjDir}fvi.c.x Ä :main:fvi.c {ObjDir}game.c.x Ä :main:game.c {ObjDir}gamecntl.c.x Ä :main:gamecntl.c {ObjDir}gamefont.c.x Ä :main:gamefont.c {ObjDir}gamemine.c.x Ä :main:gamemine.c {ObjDir}gamerend.c.x Ä :main:gamerend.c {ObjDir}gamesave.c.x Ä :main:gamesave.c {ObjDir}gameseg.c.x Ä :main:gameseg.c {ObjDir}gameseq.c.x Ä :main:gameseq.c {ObjDir}gauges.c.x Ä :main:gauges.c {ObjDir}hash.c.x Ä :main:hash.c {ObjDir}hostage.c.x Ä :main:hostage.c {ObjDir}hud.c.x Ä :main:hud.c {ObjDir}inferno.c.x Ä :main:inferno.c {ObjDir}kconfig.c.x Ä :main:kconfig.c {ObjDir}kmatrix.c.x Ä :main:kmatrix.c {ObjDir}laser.c.x Ä :main:laser.c {ObjDir}lighting.c.x Ä :main:lighting.c {ObjDir}menu.c.x Ä :main:menu.c {ObjDir}mglobal.c.x Ä :main:mglobal.c {ObjDir}mission.c.x Ä :main:mission.c {ObjDir}morph.c.x Ä :main:morph.c {ObjDir}multi.c.x Ä :main:multi.c {ObjDir}multibot.c.x Ä :main:multibot.c {ObjDir}net_ipx.c.x Ä :main:net_ipx.c {ObjDir}net_udp.c.x Ä :main:net_udp.c {ObjDir}newdemo.c.x Ä :main:newdemo.c {ObjDir}newmenu.c.x Ä :main:newmenu.c {ObjDir}object.c.x Ä :main:object.c {ObjDir}paging.c.x Ä :main:paging.c {ObjDir}physics.c.x Ä :main:physics.c {ObjDir}piggy.c.x Ä :main:piggy.c {ObjDir}player.c.x Ä :main:player.c {ObjDir}playsave.c.x Ä :main:playsave.c {ObjDir}polyobj.c.x Ä :main:polyobj.c {ObjDir}powerup.c.x Ä :main:powerup.c {ObjDir}render.c.x Ä :main:render.c {ObjDir}robot.c.x Ä :main:robot.c {ObjDir}scores.c.x Ä :main:scores.c {ObjDir}slew.c.x Ä :main:slew.c {ObjDir}snddecom.c.x Ä :main:snddecom.c {ObjDir}songs.c.x Ä :main:songs.c {ObjDir}state.c.x Ä :main:state.c {ObjDir}switch.c.x Ä :main:switch.c {ObjDir}terrain.c.x Ä :main:terrain.c {ObjDir}texmerge.c.x Ä :main:texmerge.c {ObjDir}text.c.x Ä :main:text.c {ObjDir}titles.c.x Ä :main:titles.c {ObjDir}vclip.c.x Ä :main:vclip.c {ObjDir}wall.c.x Ä :main:wall.c {ObjDir}weapon.c.x Ä :main:weapon.c {ObjDir}fixc.c.x Ä :maths:fixc.c {ObjDir}rand.c.x Ä :maths:rand.c {ObjDir}tables.c.x Ä :maths:tables.c {ObjDir}vecmat.c.x Ä :maths:vecmat.c {ObjDir}mem.c.x Ä :mem:mem.c {ObjDir}args.c.x Ä :misc:args.c {ObjDir}dl_list.c.x Ä :misc:dl_list.c {ObjDir}error.c.x Ä :misc:error.c {ObjDir}hmp.c.x Ä :misc:hmp.c {ObjDir}ignorecase.c.x Ä :misc:ignorecase.c {ObjDir}physfsx.c.x Ä :misc:physfsx.c {ObjDir}strio.c.x Ä :misc:strio.c {ObjDir}strutil.c.x Ä :misc:strutil.c {ObjDir}ntmap.c.x Ä :texmap:ntmap.c {ObjDir}scanline.c.x Ä :texmap:scanline.c {ObjDir}tmapflat.c.x Ä :texmap:tmapflat.c {ObjDir}tmapppc.a.x Ä :texmap:tmapppc.a ### Optional Dependencies ### ### Build this target to generate "include file" dependencies. ### Dependencies Ä $OutOfDate MakeDepend ¶ -append {MAKEFILE} ¶ -ignore "{CIncludes}" ¶ -objdir "{ObjDir}" ¶ -objext .x ¶ {Includes} ¶ {SrcFiles} dxx-rebirth-0.58.1-d1x/English.lproj/000077500000000000000000000000001217717257200172705ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/English.lproj/InfoPlist.strings000077500000000000000000000010441217717257200226140ustar00rootroot00000000000000þÿ/* Localized versions of Info.plist keys */ CFBundleName = "D1X"; CFBundleShortVersionString = "D1X-Rebirth v0.57.3"; CFBundleGetInfoString = "D1X-Rebirth v0.57.3, Copyright 2012 Christian Beckhaeuser."; NSHumanReadableCopyright = "Copyright 2012 Christian Beckhaeuser."; dxx-rebirth-0.58.1-d1x/INSTALL.txt000066400000000000000000000146641217717257200164340ustar00rootroot00000000000000Compiling D1X-Rebirth Sourcecode This file describes how to compile D1X-Rebirth from Source. Requirements: ============= 1. C/C++ compiler (gcc/g++) 2. SCons (to compile in *NIX/Win32) / XCode (to compile on MacOS) 3. SDL(-devel) 4. PhysFS(-devel) 5. GLU/GL 6. NASM (optional for Assembler-based Texture-mapper in non-OpenGL Build) 7. SDL_mixer(-devel) (+ dependencies) for external music support Compiling: ========== *NIX: ----- Type 'scons' to compile the source. You can also give additional options like 'scons use_udp=0'. See 'scons -h' for available options. To install, use 'scons install' but remember to use all your options as well or SCons will re-compile and install without any options given to prior compiling. However it's STRONGLY recommended NOT to use the 'install' argument but to create a package for your Linux distribution or operating system. 'install' will compile the resulting binary (d1x-rebirth) to /usr/local/bin/ by default so to uninstall, just delete the binary. MacOS: ------ For Mac OS X, an Xcode project is available (requires Xcode 2.1 or later). Xcode includes the compiler and OpenGL. The standard SDL and SDL_mixer libraries from the SDL website may be used, these go in /Library/Frameworks or ~/Library/Frameworks. However, to fix MP3 support for the 'Release' build I used SDL 1.2.8 with Diedel's modified SMPEG library from his D2X-XL website. To debug these libraries compile the frameworks from source as 'Debug' builds, then use these instead. PhysicsFS must be compiled from source. Put its enclosing folder 'physfs', renaming if necessary, next to D1X's (typically d1x-rebirth). In CMake ensure the build path points to 'build' inside 'physfs'. Specify 'i386;ppc' as the architecture for a universal binary. In Xcode, build 'Debug' and 'Release' from the dynamic library target. SCons also works on MacOS X, but it's recommended to use XCode instead. For Mac OS 9, an MPW Makefile is available. MPW includes the compiler. As for the shared libraries, compile PhysicsFS version 1.0 and the latest SDL and SDL_mixer (as of writing) from source. For SDL_mixer 1.2.11 you will need to disable MikMod support, from SDL_mixer.make, otherwise use SDL_mixer 1.2.8. For any sources to compile, they will need to be made into text files using a typecode changing program, if they were downloaded outside of Mac OS 9 (including Mac OS X). This will also need to be done after any Terminal command (diff, svn update etc) edits the source files. Note that there are ready-to-go packages on http://www.dxx-rebirth.com Win32: ------ Use the SCons way like described in the *NIX-instructions from an MSYS/MinGW environment. However you will not need to use 'install' but just drag the resulting binary to your Descent-folder. Note that there are ready-to-go packages on http://www.dxx-rebirth.com Needed files: ============= Since D1X-Rebirth is a Sourceport of the Descent-Engine you will need the Game-Content data files to run the game. You don't own the full game, yet? Just visit GOOD OLD GAMES via: http://www.gog.com/en/gamecard/descent_1_descent_2/pp/fc074d501302eb2b93e2554793fcaf50b3bf7291 and download it for a very low price! DRM-FREE! Following files are needed to run the game: descent.hog descent.pig For the Mac CD-ROM, download The Unarchiver (http://wakaba.c3.cx/s/apps/unarchiver.html) and drag the installer program onto it. Alternatively, for Mac OS 9 or earlier simply run the installer. Of course you can also use the Shareware game content with D1X-Rebirth which you can find here: http://www.dxx-rebirth.com/game-content/ For the PC CD-ROM, these files should be located on the Descent1 CD-Rom. The PC version data files need to be patched to version 1.4a. There is a patch suitable for Mac OS X available at: http://www.dxx-rebirth.com/download/dxx/misc/descent-game-content-10to14a-patch.zip To play the Multiplayer levelset 'Total Chaos', make sure the files chaos.hog chaos.msn are in the subdirectory 'Missions'. These files should also be located on the Descent1 CD. For the Mac CD data, simply move these files, after installing, from 'Data' to 'Missions'. Where to put these files: ========================= *NIX ---- The Sharepath (/usr/local/share/games/d1x-rebirth/ by default - if not reconfigured via SCons) or ~/.d1x-rebirth or another directory specified by -hogdir via d1x.ini MacOS ----- Same directory as where the binary is located or another directory specified by -hogdir via d1x.ini Win32 ----- Same directory as where the binary is located another directory specified by -hogdir via d1x.ini Optional files: =============== D1X-Rebirth is expandable. You can add additional content to the game. Missions: --------- Those can be found on several websites. Add them to the game by copying them to subdirectory ‘missions/’. They can also go in subdirectories of 'missions/', unlike with the original version. A good place to find additional mission might be the Descent mission Database: http://www.dxx-rebirth.com/descent-mission-database/ Custom Music (MP3, OGG, AIF, etc.): ----------------------------------- Custom Music can be played via the CUSTOM MUSIC options by specifying it in the Sound Options menu. Please note that all custom music has to be in 44Khz format. Supported formats depend on the capabilities of SDL_mixer. AddOn Packs: ------------ Custom AddOn packs will expand the game in many differnt ways. These are usually provided as ZIP or 7Z and can easily be installed by putting them to where your game content resides (OS-dependent - see above). NO EXTRACTION OR ADDITIONAL CONFIGURATION NEEDED. You can find all official AddOns here: http://www.dxx-rebirth.com/addons/ Launching the program ===================== *NIX ---- After compiling and installing, the program can be launched with the command: d1x-rebirth MacOS ----- Simply double-click "D1X-Rebirth". Win32 ----- Doubleclick d1x-rebirth.exe To see a full list of available command-line options append ‘-h’, ‘-?’ to the command or refer file d1x.ini Appendix ======== http://DXX-Rebirth.com dxx-rebirth-0.58.1-d1x/README.RPi000066400000000000000000000060201217717257200161210ustar00rootroot00000000000000DXX-Rebirth for the Raspberry Pi BUILDING: ========= Make sure you have installed (the development packages of) all of the required libraries (libsdl, libphysfs, ...). For building, you will also need scons (and for that, python). Most linux distributions should contain all the required packages, debain/raspbian do so for sure. Using a distribution with hardfp ABI is recommended for optimal performance. I developed/tested this on a raspbian wheezy. To build directly on the device, just run: scons raspberrypi=1 [... other options (see scons -h)...] This assumes that the development files (libs/headers) for the VideoCore APIs are located in /opt/vc. You can use rpi_vc_path to specify another location. Currently, there is no direct support for crosscompiling. RUNNING: ======== The game should run with X11 or directly on the console (libsdl with fbcon/ directfb driver). NOTE: *** PLEASE USE THE 128/128MB MEMORY SPLIT *** The game might completely freeze or diplay messed up graphics in out-of-(GPU)-memory situations. If you want to run it with the 192/64MB memory split, you might be able to do so by setting the texture filter to "NONE" in the graphics options. (This disables mip mapping and reduces the memory requirements of the textures. Note that the "BILINEAR" filter still uses mipmapping). If the game freezes during the "Prepare for Descent" phase when loading a level, you probably do not have enough GPU memory. RUNNING ON X11: =============== Recommendation is to use fullscreen mode. However, you can run in "windowed" mode, too. The game will open an X11 window in that case, and the actual game output will be an overlay of the same size, but not at the same position, and always on top (and completely out of control of the X Server). Game input is still handled via the X11 window, so make sure it has the focus. RUNNING ON THE CONSOLE: ======================= libsdl supports running directly on the Linux console. While the SDL Video mode is technically not required on the RPi, we still have to use it to get all the input events we need. libsdl seems to have problems on the RPi, I always get a crash in libsdl when trying to change the resolution. To avoid such crashes, the code will try to detect if it is running on the console and activate a hack to prevent switching the resolution. Note that the in-game framebuffer resolution can still be changed, the RPi will just scale the output to the initial resolution (in "fullscreen" mode). "Windowed" mode will just result in unscaled output. As libsdl creates a black screen, you will not be able to have the "Window" on top of the linux console output :( NOTE: You might need root privileges to use the libsdl fbcon/directfb drivers. BUGS, SUGGESTIONS AND FEEDBACK: =============================== The RPi patch was written by: Marcel Heinz Send bug reports, suggestions and other feedback regarding the operation on the RPi to me via email, or post to the official dxx-rebirth forum at: http://www.dxx-rebirth.com/frm/index.php -- derhass, 2012-08-09 dxx-rebirth-0.58.1-d1x/README.txt000066400000000000000000000070211217717257200162500ustar00rootroot00000000000000 __________ __________/ D1X-Rebirth / http://www.dxx-rebirth.com 0. Introduction: ================ This version of D1X is based on livna’s release of d1x-1.43. I spend much time to improve the Sourcecode, tried to fix bugs in there and added some improvements. It is the goal of DXX-Rebirth to keep these games alive and the result is a very stable version of the Descent I port - called D1X-Rebirth. I hope you enjoy the game as you did when you played it the first time. If you have something to say about my release, feel free to contact me at zico [at] dxx-rebirth [dot] com 1. Features: ============ DXX-Rebirth has every little feature you already may know from the DOS Version of Descent and much more. For example: * Plays Descent and Descent 2 and all their AddOns and third-party levels. * DXX-Rebirth runs on your favourite Operating System. We officially support Linux (and other *NIX), Mac OS (9/X) and Windows (2000, XP, Vista, 7). Still the code can be compiled on many other systems as well. * OpenGL provides a fast and smooth rendering - even on low-end systems. * Optionally you can enbale several effects like Transparency, Colored lighting, Texture Filtering, FSAA, etc. * Thanks to SDL, a wide palette of Joysticks are supported. Also you can use more Joysticks, buttons and axes than you can ever operate in your state of evolution. * If you prefer steering your Pyro with a mouse, you will not have the problem that the movement becomes slow in high game speed. * Joystick, Keyboard and Mouse can be used simultaneously. * The games can display all resolutions and aspects supported by your Monitor, including an option for VSync. * Besides MIDI and CD-Audio (Redbook), you can play your own custom Music from your Harddrive or a separate AddOn. * Both games can utilize special AddOn packs to replace or expand the original game content. * Multiplayer via UDP protocol provides a fast and easy-to-use LAN and Online action. This includes reliable communication causing less glitches due to lost packages. * The ingame Demo-recording system has been improved. Demos are less glitchy and smaller while still still being backwards-compatible to earlier versions of the games. * Higher game speed will not cause glitches such as unacceptable fast homing projectiles, incredible high damage caused by several collisions or Fusion cannon, etc. * Player files, Savegames, Demos and Missions from DOS-Versions of the games can freely be used in DXX-Rebirth and vice versa. * Mac Command keys are now working - see F1 Help. Command-Q works much like a normal Mac program * Even more ... 2. Installation: ================ See INSTALL.txt. 3. Multiplayer: =============== D1X-Rebirth supports Multiplayer over UDP/IP. Using UDP/IP works over LAN and Internet. By default, each game communicates over UDP-Port 42424. This can be changed via the menus while creating a game and manually join a game, command-line argument or D1X.INI. To successfully host a game online, make sure UDP-Port 42424 (or otherwise if specified correctly) is opened on your Router/Firewall. Clients do not need to open any ports. The game also supports IPv6 if built in while compiling and should be backwards compatible to IPv4 builds as good as possible. 4. Legal stuff: =============== See COPYING.txt 5. Contact: =========== http://www.dxx-rebirth.com/ zico [at] dxx-rebirth [dot] com dxx-rebirth-0.58.1-d1x/RELEASE-NOTES.txt000066400000000000000000000032571217717257200172700ustar00rootroot00000000000000RELEASE NOTES ============= What's new in 0.58.1 -------------------- * Fixed some bugs regarding reactor, making the game virtually unplayable for a lot of people What's new in 0.58.0 -------------------- * Several fixes and improvements for Multiplayer - especially Coop savestates * Sensitivity/Ramping sliders for keyboard input * More efficient postional data for Multiplayer, making ship positions more accurate and require less traffic (Thanks to v66r) * New file extension for AddOns (.dxa) * Key combination ALT+ENTER will not work ingame anymore to not interrupt player input * Command-line option to disable mouse cursor without disabling the mouse altogether * Support for Raspberry Pi by derhass * HUD style "no HUD" * Fixes for lighting code which wasn't updating correctly all the time * Improvement for transparency effects that won't make certain sprites disappear in front of bright surfaces * Support for hmp tempo setting (Thanks to Yarn) * Improvements and fixes for Shareware/Demo data * Improvements for firing mechanism, keeping fire rate accurate at all FPS * More fixes and improvements (see CHANGELOG.txt) Special notes for this release ------------------------------ * AddOns now use filename extension ".dxa". Your old AddOns will not work anymore. You can either re-download them or simply rename them from *.zip to *.dxa. Known issues ------------ * On Windows the mouse is not correctly released if using ALT+TAB to minimize the game. This is not a bug in the program but rather the SDL library. It can be worked around by pausing the game and using ALT+ENTER to get the game to windowed mode. The mosue should not be stuck then anymore. dxx-rebirth-0.58.1-d1x/SConstruct000066400000000000000000000525331217717257200166140ustar00rootroot00000000000000#SConstruct # needed imports import sys import os import SCons.Util class argumentIndirection: def __init__(self,prefix): self.prefix = prefix self.ARGUMENTS = ARGUMENTS def get(self,name,value): return self.ARGUMENTS.get('%s_%s' % (self.prefix, name), self.ARGUMENTS.get(name,value)) # endianess-checker def checkEndian(): import struct array = struct.pack('cccc', '\x01', '\x02', '\x03', '\x04') i = struct.unpack('i', array) if i == struct.unpack('i', array): return "big" return "unknown" class DXXCommon: __endian = checkEndian() class UserSettings: def __init__(self,ARGUMENTS): # Paths for the Videocore libs/includes on the Raspberry Pi self.RPI_DEFAULT_VC_PATH='/opt/vc' self.debug = int(ARGUMENTS.get('debug', 0)) self.profiler = int(ARGUMENTS.get('profiler', 0)) self.opengl = int(ARGUMENTS.get('opengl', 1)) self.asm = int(ARGUMENTS.get('asm', 0)) self.editor = int(ARGUMENTS.get('editor', 0)) self.extra_version = ARGUMENTS.get('extra_version', None) self.sdlmixer = int(ARGUMENTS.get('sdlmixer', 1)) self.ipv6 = int(ARGUMENTS.get('ipv6', 0)) self.use_udp = int(ARGUMENTS.get('use_udp', 1)) self.use_tracker = int(ARGUMENTS.get('use_tracker', 1)) self.verbosebuild = int(ARGUMENTS.get('verbosebuild', 0)) self.raspberrypi = int(ARGUMENTS.get('raspberrypi', 0)) self.rpi_vc_path = str(ARGUMENTS.get('rpi_vc_path', self.RPI_DEFAULT_VC_PATH)) self.default_opengles = 0 self.default_OGLES_LIB = 'GLES_CM' # automatic setup for raspberrypi if (self.raspberrypi == 1): self.default_opengles=1 self.default_OGLES_LIB='GLESv2' self.opengles = int(ARGUMENTS.get('opengles', self.default_opengles)) self.opengles_lib = str(ARGUMENTS.get('opengles_lib', self.default_OGLES_LIB)) builddir_prefix = ARGUMENTS.get('builddir_prefix', None) builddir_suffix = ARGUMENTS.get('builddir_suffix', None) default_builddir = builddir_prefix or '' if builddir_prefix is not None or builddir_suffix is not None: if os.environ.has_key('CC'): default_builddir += '%s-' % os.path.basename(os.environ['CC']) for a in ( ('debug', 'dbg'), ('profiler', 'prf'), ('editor', 'ed'), ('opengl', 'ogl'), ('opengles', 'es'), ): if getattr(self, a[0]): default_builddir += a[1] if builddir_suffix is not None: default_builddir += builddir_prefix self.builddir = ARGUMENTS.get('builddir', default_builddir) if self.builddir != '' and self.builddir[-1:] != '/': self.builddir += '/' # Base class for platform-specific settings processing class _PlatformSettings: tools = None ogllibs = '' osasmdef = None platform_sources = [] platform_objects = [] # Settings to apply to mingw32 builds class Win32PlatformSettings(_PlatformSettings): tools = ['mingw'] osdef = '_WIN32' osasmdef = 'win32' def __init__(self,user_settings): pass def adjust_environment(self,program,env): env.Append(CPPDEFINES = ['_WIN32', 'HAVE_STRUCT_TIMEVAL']) class DarwinPlatformSettings(_PlatformSettings): osdef = '__APPLE__' def __init__(self,user_settings): user_settings.asm = 0 self.lflags = os.environ["LDFLAGS"] if os.environ.has_key('LDFLAGS') else '' def adjust_environment(self,program,env): VERSION = str(program.VERSION_MAJOR) + '.' + str(program.VERSION_MINOR) if (program.VERSION_MICRO): VERSION += '.' + str(program.VERSION_MICRO) env['VERSION_NUM'] = VERSION env['VERSION_NAME'] = program.PROGRAM_NAME + ' v' + VERSION env.Append(CPPDEFINES = ['HAVE_STRUCT_TIMESPEC', 'HAVE_STRUCT_TIMEVAL', '__unix__']) env.Append(CPPPATH = [os.path.join(program.srcdir, '../physfs'), os.path.join(os.getenv("HOME"), 'Library/Frameworks/SDL.framework/Headers'), '/Library/Frameworks/SDL.framework/Headers']) env.Append(FRAMEWORKS = ['ApplicationServices', 'Carbon', 'Cocoa', 'SDL']) env.Append(FRAMEWORKPATH = [os.path.join(os.getenv("HOME"), 'Library/Frameworks'), '/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks']) self.libs = [''] env['LIBPATH'] = '../physfs/build/Debug' # Settings to apply to Linux builds class LinuxPlatformSettings(_PlatformSettings): osdef = '__LINUX__' osasmdef = 'elf' __opengl_libs = ['GL', 'GLU'] __pkg_config_sdl = {} def __init__(self,user_settings): if (user_settings.opengles == 1): self.ogllibs = [ user_settings.opengles_lib, 'EGL'] else: self.ogllibs = self.__opengl_libs def adjust_environment(self,program,env): env.Append(CPPDEFINES = ['__LINUX__', 'HAVE_STRUCT_TIMESPEC', 'HAVE_STRUCT_TIMEVAL']) try: pkgconfig = os.environ['PKG_CONFIG'] except KeyError as e: try: pkgconfig = '%s-pkg-config' % os.environ['CHOST'] except KeyError as e: pkgconfig = 'pkg-config' cmd = '%s --cflags --libs sdl' % pkgconfig try: flags = self.__pkg_config_sdl[cmd] except KeyError as e: if (program.user_settings.verbosebuild != 0): print "%s: reading SDL settings from `%s`" % (program.PROGRAM_NAME, cmd) self.__pkg_config_sdl[cmd] = env.backtick(cmd) flags = self.__pkg_config_sdl[cmd] env.MergeFlags(flags) def __init__(self): pass def prepare_environment(self): if self.user_settings.builddir != '': self.env.VariantDir(self.user_settings.builddir, '.', duplicate=0) # Prettier build messages...... if (self.user_settings.verbosebuild == 0): self.env["CCCOMSTR"] = "Compiling $SOURCE ..." self.env["CXXCOMSTR"] = "Compiling $SOURCE ..." self.env["LINKCOMSTR"] = "Linking $TARGET ..." self.env["ARCOMSTR"] = "Archiving $TARGET ..." self.env["RANLIBCOMSTR"] = "Indexing $TARGET ..." self.env.Append(CCFLAGS = ['-Wall', '-funsigned-char', '-Werror=implicit-int', '-Werror=implicit-function-declaration', '-pthread']) self.env.Append(CFLAGS = ['-std=gnu99']) self.env.Append(CPPDEFINES = ['NETWORK']) # Get traditional compiler environment variables for cc in ['CC', 'CXX']: if os.environ.has_key(cc): self.env[cc] = os.environ[cc] for flags in ['CFLAGS', 'CXXFLAGS']: if os.environ.has_key(flags): self.env[flags] += SCons.Util.CLVar(os.environ[flags]) def check_endian(self): # set endianess if (self.__endian == "big"): print "%s: BigEndian machine detected" % self.PROGRAM_NAME self.asm = 0 self.env.Append(CPPDEFINES = ['WORDS_BIGENDIAN']) elif (self.__endian == "little"): print "%s: LittleEndian machine detected" % self.PROGRAM_NAME def check_platform(self): # windows or *nix? if sys.platform == 'win32': print "%s: compiling on Windows" % self.PROGRAM_NAME platform = self.Win32PlatformSettings elif sys.platform == 'darwin': print "%s: compiling on Mac OS X" % self.PROGRAM_NAME platform = self.DarwinPlatformSettings else: print "%s: compiling on *NIX" % self.PROGRAM_NAME platform = self.LinuxPlatformSettings self.platform_settings = platform(self.user_settings) # Acquire environment object... self.env = Environment(ENV = os.environ, tools = platform.tools) self.platform_settings.adjust_environment(self, self.env) self.platform_settings.libs += ['physfs', 'm'] self.common_sources += self.platform_settings.platform_sources def process_user_settings(self): env = self.env # opengl or software renderer? if (self.user_settings.opengl == 1) or (self.user_settings.opengles == 1): if (self.user_settings.opengles == 1): print "%s: building with OpenGL ES" % self.PROGRAM_NAME env.Append(CPPDEFINES = ['OGLES']) else: print "%s: building with OpenGL" % self.PROGRAM_NAME env.Append(CPPDEFINES = ['OGL']) # assembler code? if (self.user_settings.asm == 1) and (self.user_settings.opengl == 0): print "%s: including: ASSEMBLER" % self.PROGRAM_NAME env.Replace(AS = 'nasm') env.Append(ASCOM = ' -f ' + str(self.platform_settings.osasmdef) + ' -d' + str(self.platform_settings.osdef) + ' -Itexmap/ ') self.common_sources += asm_sources else: env.Append(CPPDEFINES = ['NO_ASM']) # SDL_mixer support? if (self.user_settings.sdlmixer == 1): print "%s: including SDL_mixer" % self.PROGRAM_NAME env.Append(CPPDEFINES = ['USE_SDLMIXER']) # debug? if (self.user_settings.debug == 1): print "%s: including: DEBUG" % self.PROGRAM_NAME env.Append(CPPFLAGS = ['-g']) else: env.Append(CPPDEFINES = ['NDEBUG', 'RELEASE']) env.Append(CPPFLAGS = ['-O2']) # profiler? if (self.user_settings.profiler == 1): env.Append(CPPFLAGS = ['-pg']) #editor build? if (self.user_settings.editor == 1): env.Append(CPPDEFINES = ['EDITOR']) self.common_sources += self.editor_sources # IPv6 compability? if (self.user_settings.ipv6 == 1): env.Append(CPPDEFINES = ['IPv6']) # UDP support? if (self.user_settings.use_udp == 1): env.Append(CPPDEFINES = ['USE_UDP']) # Tracker support? (Relies on UDP) if( self.user_settings.use_tracker == 1 ): env.Append( CPPDEFINES = [ 'USE_TRACKER' ] ) # Raspberry Pi? if (self.user_settings.raspberrypi == 1): print "using Raspberry Pi vendor libs in %s" % self.user_settings.rpi_vc_path env.Append(CPPDEFINES = ['RPI', 'WORDS_NEED_ALIGNMENT']) env.Append(CPPPATH = [ self.user_settings.rpi_vc_path+'/include', self.user_settings.rpi_vc_path+'/include/interface/vcos/pthreads', self.user_settings.rpi_vc_path+'/include/interface/vmcs_host/linux']) self.platform_settings.lflags += ' -L' + self.user_settings.rpi_vc_path + '/lib' self.platform_settings.libs += ['bcm_host'] class DXXProgram(DXXCommon): # version number VERSION_MAJOR = 0 VERSION_MINOR = 58 VERSION_MICRO = 1 class UserSettings(DXXCommon.UserSettings): def __init__(self,ARGUMENTS,target): DXXCommon.UserSettings.__init__(self, ARGUMENTS.ARGUMENTS) # installation path PREFIX = str(ARGUMENTS.get('prefix', '/usr/local')) self.BIN_DIR = PREFIX + '/bin' self.DATA_DIR = PREFIX + '/share/games/' + target # command-line parms self.sharepath = str(ARGUMENTS.get('sharepath', self.DATA_DIR)) # Settings to apply to mingw32 builds class Win32PlatformSettings(DXXCommon.Win32PlatformSettings): def __init__(self,user_settings): DXXCommon.Win32PlatformSettings.__init__(self,user_settings) user_settings.sharepath = '' self.lflags = '-mwindows' self.libs = ['glu32', 'wsock32', 'ws2_32', 'winmm', 'mingw32', 'SDLmain', 'SDL'] def adjust_environment(self,program,env): DXXCommon.Win32PlatformSettings.adjust_environment(self, program, env) env.Append(CPPPATH = [os.path.join(program.srcdir, 'arch/win32/include')]) self.platform_sources = [os.path.join(program.srcdir, 'arch/win32/messagebox.c')] rcbasename = 'arch/win32/%s' % program.target self.platform_objects = [env.RES(target='%s%s%s' % (program.user_settings.builddir, rcbasename, env["OBJSUFFIX"]), source='%s.rc' % rcbasename)] # Settings to apply to Apple builds # This appears to be unused. The reference to sdl_only fails to # execute. class DarwinPlatformSettings(DXXCommon.DarwinPlatformSettings): def __init__(self,user_settings): DXXCommon.DarwinPlatformSettings.__init__(self) user_settings.sharepath = '' def adjust_environment(self,program,env): DXXCommon.DarwinPlatformSettings.adjust_environment(self, program, env) self.platform_sources = [os.path.join(program.srcdir, f) for f in ['arch/cocoa/SDLMain.m', 'arch/carbon/messagebox.c']] # Settings to apply to Linux builds class LinuxPlatformSettings(DXXCommon.LinuxPlatformSettings): def __init__(self,user_settings): DXXCommon.LinuxPlatformSettings.__init__(self,user_settings) user_settings.sharepath += '/' self.lflags = os.environ["LDFLAGS"] if os.environ.has_key('LDFLAGS') else '' def adjust_environment(self,program,env): DXXCommon.LinuxPlatformSettings.adjust_environment(self, program, env) self.libs = env['LIBS'] env.Append(CPPPATH = [os.path.join(program.srcdir, 'arch/linux/include')]) def __init__(self): DXXCommon.__init__(self) self.user_settings = self.UserSettings(self.ARGUMENTS, self.target) self.check_platform() self.prepare_environment() self.banner() self.check_endian() self.process_user_settings() self.register_program() def prepare_environment(self): DXXCommon.prepare_environment(self) self.VERSION_STRING = ' v' + str(self.VERSION_MAJOR) + '.' + str(self.VERSION_MINOR) + '.' + str(self.VERSION_MICRO) self.env.Append(CPPDEFINES = [('DXX_VERSION_MAJORi', str(self.VERSION_MAJOR)), ('DXX_VERSION_MINORi', str(self.VERSION_MINOR)), ('DXX_VERSION_MICROi', str(self.VERSION_MICRO))]) def banner(self): print '\n===== ' + self.PROGRAM_NAME + self.VERSION_STRING + ' =====\n' def process_user_settings(self): DXXCommon.process_user_settings(self) env = self.env # opengl or software renderer? if (self.user_settings.opengl == 1) or (self.user_settings.opengles == 1): self.common_sources += self.arch_ogl_sources if (sys.platform != 'darwin'): self.platform_settings.libs += self.platform_settings.ogllibs else: env.Append(FRAMEWORKS = ['OpenGL']) else: print "%s: building with Software Renderer" % self.PROGRAM_NAME self.common_sources += self.arch_sdl_sources # SDL_mixer support? if (self.user_settings.sdlmixer == 1): self.common_sources += self.arch_sdlmixer if (sys.platform != 'darwin'): self.platform_settings.libs += ['SDL_mixer'] else: env.Append(FRAMEWORKS = ['SDL_mixer']) # profiler? if (self.user_settings.profiler == 1): self.platform_settings.lflags += ' -pg' #editor build? if (self.user_settings.editor == 1): env.Append(CPPPATH = [os.path.join(self.srcdir, 'include/editor')]) # UDP support? if (self.user_settings.use_udp == 1): self.common_sources += self.sources_use_udp env.Append(CPPDEFINES = [('SHAREPATH', '\\"' + str(self.user_settings.sharepath) + '\\"')]) def _register_program(self,dxxstr,program_specific_objects=[]): env = self.env exe_target = os.path.join(self.srcdir, self.target) objects = [self.env.StaticObject(target='%s%s%s' % (self.user_settings.builddir, os.path.splitext(s)[0], self.env["OBJSUFFIX"]), source=s) for s in self.common_sources] objects.extend(self.platform_settings.platform_objects) objects.extend(program_specific_objects) versid_cppdefines=env['CPPDEFINES'][:] if self.user_settings.extra_version: versid_cppdefines.append(('DESCENT_VERSION_EXTRA', '\\"%s\\"' % self.user_settings.extra_version)) objects.append(self.env.StaticObject(target='%s%s%s' % (self.user_settings.builddir, 'main/vers_id', self.env["OBJSUFFIX"]), source='main/vers_id.c', CPPDEFINES=versid_cppdefines)) # finally building program... env.Program(target='%s%s' % (self.user_settings.builddir, str(exe_target)), source = objects, LIBS = self.platform_settings.libs, LINKFLAGS = str(self.platform_settings.lflags)) if (sys.platform != 'darwin'): env.Install(self.user_settings.BIN_DIR, str(exe_target)) env.Alias('install', self.user_settings.BIN_DIR) else: sys.path += ['./arch/cocoa'] import tool_bundle tool_bundle.TOOL_BUNDLE(env) env.MakeBundle(self.PROGRAM_NAME + '.app', exe_target, 'free.%s-rebirth' % dxxstr, '%sgl-Info.plist' % dxxstr, typecode='APPL', creator='DCNT', icon_file='arch/cocoa/%s-rebirth.icns' % dxxstr, subst_dict={'%sgl' % dxxstr : exe_target}, # This is required; manually update version for Xcode compatibility resources=[['English.lproj/InfoPlist.strings', 'English.lproj/InfoPlist.strings']]) class D1XProgram(DXXProgram): PROGRAM_NAME = 'D1X-Rebirth' target = 'd1x-rebirth' srcdir = '' ARGUMENTS = argumentIndirection('d1x') def prepare_environment(self): DXXProgram.prepare_environment(self) # Flags and stuff for all platforms... self.env.Append(CPPPATH = [os.path.join(self.srcdir, f) for f in ['include', 'main', 'arch/include']]) def __init__(self): # general source files self.common_sources = [os.path.join(self.srcdir, f) for f in [ '2d/2dsline.c', '2d/bitblt.c', '2d/bitmap.c', '2d/box.c', '2d/canvas.c', '2d/circle.c', '2d/disc.c', '2d/font.c', '2d/gpixel.c', '2d/line.c', '2d/palette.c', '2d/pcx.c', '2d/pixel.c', '2d/poly.c', '2d/rect.c', '2d/rle.c', '2d/scalec.c', '3d/clipper.c', '3d/draw.c', '3d/globvars.c', '3d/instance.c', '3d/interp.c', '3d/matrix.c', '3d/points.c', '3d/rod.c', '3d/setup.c', 'arch/sdl/event.c', 'arch/sdl/init.c', 'arch/sdl/joy.c', 'arch/sdl/key.c', 'arch/sdl/mouse.c', 'arch/sdl/rbaudio.c', 'arch/sdl/timer.c', 'arch/sdl/window.c', 'arch/sdl/digi.c', 'arch/sdl/digi_audio.c', 'iff/iff.c', 'main/ai.c', 'main/aipath.c', 'main/automap.c', 'main/bm.c', 'main/bmread.c', 'main/cntrlcen.c', 'main/collide.c', 'main/config.c', 'main/console.c', 'main/controls.c', 'main/credits.c', 'main/custom.c', 'main/digiobj.c', 'main/dumpmine.c', 'main/effects.c', 'main/endlevel.c', 'main/fireball.c', 'main/fuelcen.c', 'main/fvi.c', 'main/game.c', 'main/gamecntl.c', 'main/gamefont.c', 'main/gamemine.c', 'main/gamerend.c', 'main/gamesave.c', 'main/gameseg.c', 'main/gameseq.c', 'main/gauges.c', 'main/hostage.c', 'main/hud.c', 'main/inferno.c', 'main/kconfig.c', 'main/kmatrix.c', 'main/laser.c', 'main/lighting.c', 'main/menu.c', 'main/mglobal.c', 'main/mission.c', 'main/morph.c', 'main/multi.c', 'main/multibot.c', 'main/newdemo.c', 'main/newmenu.c', 'main/object.c', 'main/paging.c', 'main/physics.c', 'main/piggy.c', 'main/player.c', 'main/playsave.c', 'main/polyobj.c', 'main/powerup.c', 'main/render.c', 'main/robot.c', 'main/scores.c', 'main/slew.c', 'main/snddecom.c', 'main/songs.c', 'main/state.c', 'main/switch.c', 'main/terrain.c', 'main/texmerge.c', 'main/text.c', 'main/titles.c', 'main/vclip.c', 'main/wall.c', 'main/weapon.c', 'maths/fixc.c', 'maths/rand.c', 'maths/tables.c', 'maths/vecmat.c', 'mem/mem.c', 'misc/args.c', 'misc/dl_list.c', 'misc/error.c', 'misc/hash.c', 'misc/hmp.c', 'misc/ignorecase.c', 'misc/physfsx.c', 'misc/strio.c', 'misc/strutil.c', 'texmap/ntmap.c', 'texmap/scanline.c' #'tracker/client/tracker_client.c' ] ] # for editor self.editor_sources = [os.path.join(self.srcdir, f) for f in [ 'editor/centers.c', 'editor/curves.c', 'editor/autosave.c', 'editor/eglobal.c', 'editor/ehostage.c', 'editor/elight.c', 'editor/eobject.c', 'editor/eswitch.c', 'editor/fixseg.c', 'editor/func.c', 'editor/group.c', 'editor/info.c', 'editor/kbuild.c', 'editor/kcurve.c', 'editor/kfuncs.c', 'editor/kgame.c', 'editor/khelp.c', 'editor/kmine.c', 'editor/ksegmove.c', 'editor/ksegsel.c', 'editor/ksegsize.c', 'editor/ktmap.c', 'editor/kview.c', 'editor/med.c', 'editor/meddraw.c', 'editor/medmisc.c', 'editor/medrobot.c', 'editor/medsel.c', 'editor/medwall.c', 'editor/mine.c', 'editor/objpage.c', 'editor/segment.c', 'editor/seguvs.c', 'editor/texpage.c', 'editor/texture.c', 'ui/button.c', 'ui/checkbox.c', 'ui/dialog.c', 'ui/file.c', 'ui/gadget.c', 'ui/icon.c', 'ui/inputbox.c', 'ui/keypad.c', 'ui/keypress.c', 'ui/keytrap.c', 'ui/listbox.c', 'ui/menu.c', 'ui/menubar.c', 'ui/message.c', 'ui/popup.c', 'ui/radio.c', 'ui/scroll.c', 'ui/ui.c', 'ui/uidraw.c', 'ui/userbox.c' ] ] DXXProgram.__init__(self) sources_use_udp = [os.path.join(srcdir, 'main/net_udp.c')] # SDL_mixer sound implementation arch_sdlmixer = [os.path.join(srcdir, f) for f in [ 'arch/sdl/digi_mixer.c', 'arch/sdl/digi_mixer_music.c', 'arch/sdl/jukebox.c' ] ] # for opengl arch_ogl_sources = [os.path.join(srcdir, f) for f in [ 'arch/ogl/gr.c', 'arch/ogl/ogl.c', ] ] # for non-ogl arch_sdl_sources = [os.path.join(srcdir, f) for f in [ 'arch/sdl/gr.c', 'texmap/tmapflat.c' ] ] # assembler related asm_sources = [os.path.join(srcdir, f) for f in [ 'texmap/tmap_ll.asm', 'texmap/tmap_flt.asm', 'texmap/tmapfade.asm', 'texmap/tmap_lin.asm', 'texmap/tmap_per.asm' ] ] def register_program(self): self._register_program('d1x') program = D1XProgram() # show some help when running scons -h Help(program.PROGRAM_NAME + ', SConstruct file help:' + """ Type 'scons' to build the binary. Type 'scons install' to build (if it hasn't been done) and install. Type 'scons -c' to clean up. Extra options (add them to command line, like 'scons extraoption=value'): 'sharepath=[DIR]' (non-Mac OS *NIX only) use [DIR] for shared game data. [default: /usr/local/share/games/d1x-rebirth] 'opengl=[0/1]' build with OpenGL support [default: 1] 'opengles=[0/1]' build with OpenGL ES support [default: 0] 'sdlmixer=[0/1]' build with SDL_Mixer support for sound and music (includes external music support) [default: 1] 'asm=[0/1]' build with ASSEMBLER code (only with opengl=0, requires NASM and x86) [default: 0] 'debug=[0/1]' build DEBUG binary which includes asserts, debugging output, cheats and more output [default: 0] 'profiler=[0/1]' profiler build [default: 0] 'editor=[0/1]' include editor into build (!EXPERIMENTAL!) [default: 0] 'ipv6=[0/1]' enable IPv6 compability [default: 0] 'use_udp=[0/1]' enable UDP support [default: 1] 'use_tracker=[0/1]' enable Tracker support (requires udp) [default :1] 'verbosebuild=[0/1]' print out all compiler/linker messages during building [default: 0] 'raspberrypi=[0/1]' build for Raspberry Pi (automatically sets opengles and opengles_lib) [default: 0] 'rpi_vc_path=[DIR]' use [DIR] to look for VideoCore libraries/header files (RPi only) Default values: """ + ' sharepath = ' + program.user_settings.DATA_DIR + """ Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags """) #EOF dxx-rebirth-0.58.1-d1x/arch/000077500000000000000000000000001217717257200154675ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/carbon/000077500000000000000000000000001217717257200167335ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/carbon/SDL_main.c000066400000000000000000000362441217717257200205360ustar00rootroot00000000000000/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2004 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org */ #ifdef SAVE_RCSID static char rcsid = "@(#) $Id: SDL_main.c,v 1.1.1.1 2006/03/17 19:54:28 zicodxx Exp $"; #endif /* This file takes care of command line argument parsing, and stdio redirection in the MacOS environment. */ #include #include #include #include #if defined(__APPLE__) && defined(__MACH__) #include #elif TARGET_API_MAC_CARBON #include #else #include #include #include #include #include #endif /* Include the SDL main definition header */ #include #include "SDL_main.h" #ifdef main #undef main #endif /* The standard output files */ #define STDOUT_FILE "stdout.txt" #define STDERR_FILE "stderr.txt" #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON /* In MPW, the qd global has been removed from the libraries */ QDGlobals qd; #endif /* Structure for keeping prefs in 1 variable */ typedef struct { Str255 command_line; Str255 video_driver_name; Boolean output_to_file; } PrefsRecord; /* See if the command key is held down at startup */ static Boolean CommandKeyIsDown(void) { KeyMap theKeyMap; GetKeys(theKeyMap); if (((unsigned char *) theKeyMap)[6] & 0x80) { return(true); } return(false); } /* Parse a command line buffer into arguments */ static int ParseCommandLine(char *cmdline, char **argv) { char *bufp; int argc; argc = 0; for ( bufp = cmdline; *bufp; ) { /* Skip leading whitespace */ while ( isspace(*bufp) ) { ++bufp; } /* Skip over argument */ if ( *bufp == '"' ) { ++bufp; if ( *bufp ) { if ( argv ) { argv[argc] = bufp; } ++argc; } /* Skip over word */ while ( *bufp && (*bufp != '"') ) { ++bufp; } } else { if ( *bufp ) { if ( argv ) { argv[argc] = bufp; } ++argc; } /* Skip over word */ while ( *bufp && ! isspace(*bufp) ) { ++bufp; } } if ( *bufp ) { if ( argv ) { *bufp = '\0'; } ++bufp; } } if ( argv ) { argv[argc] = NULL; } return(argc); } /* Remove the output files if there was no output written */ static void cleanup_output(void) { FILE *file; int empty; /* Flush the output in case anything is queued */ fclose(stdout); fclose(stderr); /* See if the files have any output in them */ file = fopen(STDOUT_FILE, "rb"); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) { remove(STDOUT_FILE); } } file = fopen(STDERR_FILE, "rb"); if ( file ) { empty = (fgetc(file) == EOF) ? 1 : 0; fclose(file); if ( empty ) { remove(STDERR_FILE); } } } static int getCurrentAppName (StrFileName name) { ProcessSerialNumber process; ProcessInfoRec process_info; FSSpec process_fsp; process.highLongOfPSN = 0; process.lowLongOfPSN = kCurrentProcess; process_info.processInfoLength = sizeof (process_info); process_info.processName = NULL; process_info.processAppSpec = &process_fsp; if ( noErr != GetProcessInformation (&process, &process_info) ) return 0; memcpy (name, process_fsp.name, process_fsp.name[0] + 1); return 1; } static int getPrefsFile (FSSpec *prefs_fsp, int create) { /* The prefs file name is the application name, possibly truncated, */ /* plus " Preferences */ #define SUFFIX " Preferences" #define MAX_NAME 19 /* 31 - strlen (SUFFIX) */ short volume_ref_number; long directory_id; StrFileName prefs_name; StrFileName app_name; /* Get Preferences folder - works with Multiple Users */ if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &volume_ref_number, &directory_id) ) exit (-1); if ( ! getCurrentAppName (app_name) ) exit (-1); /* Truncate if name is too long */ if (app_name[0] > MAX_NAME ) app_name[0] = MAX_NAME; memcpy (prefs_name + 1, app_name + 1, app_name[0]); memcpy (prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX)); prefs_name[0] = app_name[0] + strlen (SUFFIX); /* Make the file spec for prefs file */ if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) ) if ( !create ) return 0; else { /* Create the prefs file */ memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1); prefs_fsp->parID = directory_id; prefs_fsp->vRefNum = volume_ref_number; FSpCreateResFile (prefs_fsp, '????', 'pref', 0); if ( noErr != ResError () ) return 0; } return 1; } static int readPrefsResource (PrefsRecord *prefs) { Handle prefs_handle; prefs_handle = Get1Resource( 'CLne', 128 ); if (prefs_handle != NULL) { int offset = 0; HLock(prefs_handle); /* Get command line string */ memcpy (prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1); /* Get video driver name */ offset += (*prefs_handle)[0] + 1; memcpy (prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1); /* Get save-to-file option (1 or 0) */ offset += (*prefs_handle)[offset] + 1; prefs->output_to_file = (*prefs_handle)[offset]; ReleaseResource( prefs_handle ); return ResError() == noErr; } return 0; } static int writePrefsResource (PrefsRecord *prefs, short resource_file) { Handle prefs_handle; UseResFile (resource_file); prefs_handle = Get1Resource ( 'CLne', 128 ); if (prefs_handle != NULL) RemoveResource (prefs_handle); prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 ); if (prefs_handle != NULL) { int offset; HLock (prefs_handle); /* Command line text */ offset = 0; memcpy (*prefs_handle, prefs->command_line, prefs->command_line[0] + 1); /* Video driver name */ offset += prefs->command_line[0] + 1; memcpy (*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1); /* Output-to-file option */ offset += prefs->video_driver_name[0] + 1; *( *((char**)prefs_handle) + offset) = (char)prefs->output_to_file; *( *((char**)prefs_handle) + offset + 1) = 0; AddResource (prefs_handle, 'CLne', 128, "\pCommand Line"); WriteResource (prefs_handle); UpdateResFile (resource_file); DisposeHandle (prefs_handle); return ResError() == noErr; } return 0; } static int readPreferences (PrefsRecord *prefs) { int no_error = 1; FSSpec prefs_fsp; /* Check for prefs file first */ if ( getPrefsFile (&prefs_fsp, 0) ) { short prefs_resource; prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm); if ( prefs_resource == -1 ) /* this shouldn't happen, but... */ return 0; UseResFile (prefs_resource); no_error = readPrefsResource (prefs); CloseResFile (prefs_resource); } /* Fall back to application's resource fork (reading only, so this is safe) */ else { no_error = readPrefsResource (prefs); } return no_error; } static int writePreferences (PrefsRecord *prefs) { int no_error = 1; FSSpec prefs_fsp; /* Get prefs file, create if it doesn't exist */ if ( getPrefsFile (&prefs_fsp, 1) ) { short prefs_resource; prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm); if (prefs_resource == -1) return 0; no_error = writePrefsResource (prefs, prefs_resource); CloseResFile (prefs_resource); } return no_error; } /* This is where execution begins */ int main(int argc, char *argv[]) { #pragma unused(argc, argv) #define DEFAULT_ARGS "\p" /* pascal string for default args */ #define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */ #define DEFAULT_OUTPUT_TO_FILE 1 /* 1 == output to file, 0 == no output */ #define VIDEO_ID_DRAWSPROCKET 1 /* these correspond to popup menu choices */ #define VIDEO_ID_TOOLBOX 2 PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE }; int nargs; char **args; char *commandLine; StrFileName appNameText; int videodriver = VIDEO_ID_TOOLBOX; int settingsChanged = 0; long i; /* Kyle's SDL command-line dialog code ... */ #if !TARGET_API_MAC_CARBON InitGraf (&qd.thePort); InitFonts (); InitWindows (); InitMenus (); InitDialogs (nil); #endif InitCursor (); FlushEvents(everyEvent,0); #if !TARGET_API_MAC_CARBON MaxApplZone (); #endif MoreMasters (); MoreMasters (); #if 0 /* Intialize SDL, and put up a dialog if we fail */ if ( SDL_Init (0) < 0 ) { #define kErr_OK 1 #define kErr_Text 2 DialogPtr errorDialog; short dummyType; Rect dummyRect; Handle dummyHandle; short itemHit; errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1); DrawDialog (errorDialog); GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect); SetDialogItemText (dummyHandle, "\pError Initializing SDL"); SetPort (errorDialog); do { ModalDialog (nil, &itemHit); } while (itemHit != kErr_OK); DisposeDialog (errorDialog); exit (-1); } atexit(cleanup_output); atexit(SDL_Quit); #endif /* Set up SDL's QuickDraw environment */ #if !TARGET_API_MAC_CARBON SDL_InitQuickDraw(&qd); #endif if ( readPreferences (&prefs) ) { if (memcmp (prefs.video_driver_name+1, "DSp", 3) == 0) videodriver = 1; else if (memcmp (prefs.video_driver_name+1, "toolbox", 7) == 0) videodriver = 2; } if ( CommandKeyIsDown() ) { #define kCL_OK 1 #define kCL_Cancel 2 #define kCL_Text 3 #define kCL_File 4 #define kCL_Video 6 DialogPtr commandDialog; short dummyType; Rect dummyRect; Handle dummyHandle; short itemHit; /* Assume that they will change settings, rather than do exhaustive check */ settingsChanged = 1; /* Create dialog and display it */ commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1); SetPortDialogPort (commandDialog); /* Setup controls */ GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file ); GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); SetDialogItemText (dummyHandle, prefs.command_line); GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect); SetControlValue ((ControlRef)dummyHandle, videodriver); SetDialogDefaultItem (commandDialog, kCL_OK); SetDialogCancelItem (commandDialog, kCL_Cancel); do { ModalDialog(nil, &itemHit); /* wait for user response */ /* Toggle command-line output checkbox */ if ( itemHit == kCL_File ) { GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) ); } } while (itemHit != kCL_OK && itemHit != kCL_Cancel); /* Get control values, even if they did not change */ GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */ GetDialogItemText (dummyHandle, prefs.command_line); GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle); GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect); videodriver = GetControlValue ((ControlRef)dummyHandle); DisposeDialog (commandDialog); if (itemHit == kCL_Cancel ) { exit (0); } } /* Set pseudo-environment variables for video driver, update prefs */ switch ( videodriver ) { case VIDEO_ID_DRAWSPROCKET: SDL_putenv ("SDL_VIDEODRIVER=DSp"); memcpy (prefs.video_driver_name, "\pDSp", 4); break; case VIDEO_ID_TOOLBOX: SDL_putenv ("SDL_VIDEODRIVER=toolbox"); memcpy (prefs.video_driver_name, "\ptoolbox", 8); break; } /* Redirect standard I/O to files */ if ( prefs.output_to_file ) { freopen (STDOUT_FILE, "w", stdout); freopen (STDERR_FILE, "w", stderr); } else { fclose (stdout); fclose (stderr); } if (settingsChanged) { /* Save the prefs, even if they might not have changed (but probably did) */ if ( ! writePreferences (&prefs) ) fprintf (stderr, "WARNING: Could not save preferences!\n"); } getCurrentAppName (appNameText); /* check for error here ? */ commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2); if ( commandLine == NULL ) { exit(-1); } /* Rather than rewrite ParseCommandLine method, let's replace */ /* any spaces in application name with underscores, */ /* so that the app name is only 1 argument */ for (i = 1; i < 1+appNameText[0]; i++) if ( appNameText[i] == ' ' ) appNameText[i] = '_'; /* Copy app name & full command text to command-line C-string */ memcpy (commandLine, appNameText + 1, appNameText[0]); commandLine[appNameText[0]] = ' '; memcpy (commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]); commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0'; /* Parse C-string into argv and argc */ nargs = ParseCommandLine (commandLine, NULL); args = (char **)malloc((nargs+1)*(sizeof *args)); if ( args == NULL ) { exit(-1); } ParseCommandLine (commandLine, args); /* Run the main application code */ SDL_main(nargs, args); free (args); free (commandLine); /* Remove useless stdout.txt and stderr.txt */ cleanup_output (); /* Exit cleanly, calling atexit() functions */ exit (0); /* Never reached, but keeps the compiler quiet */ return (0); } dxx-rebirth-0.58.1-d1x/arch/carbon/conf.h000066400000000000000000000032311217717257200200300ustar00rootroot00000000000000/* conf.h. Generated by configure. */ /* conf.h.in. Generated from configure.ac by autoheader. */ // Modified by Chris to work for an Apple computer with OS 9 or above /* Define to enable console */ /* #undef CONSOLE */ /* d2x major version */ #define DXX_VERSION_MAJORi 0 /* d2x minor version */ #define DXX_VERSION_MINORi 58 /* d2x micro version */ #define DXX_VERSION_MICROi 1 /* Define if you want to build the editor */ /* #undef EDITOR */ /* Define if you want to build for mac datafiles */ //#define MACDATA /* Define to disable asserts, int3, etc. */ /* #undef NDEBUG */ /* Define if you want an assembler free build */ #define NO_ASM /* Define if you want an OpenGL build */ //#define OGL /* Define for a "release" build */ /* #undef RELEASE */ /* Define this to be the shared game directory root */ #define SHAREPATH "." /* Define if your processor needs data to be word-aligned */ /* #undef WORDS_NEED_ALIGNMENT */ /* General defines */ #if defined(__APPLE__) && defined(__MACH__) # define __unix__ /* Define if you want a network build */ # define NETWORK # define USE_UDP # define USE_TRACKER //#define IPv6 /* Define to 1 if the system has the type `struct timespec'. */ #define HAVE_STRUCT_TIMESPEC 1 /* Define to 1 if the system has the type `struct timeval'. */ #define HAVE_STRUCT_TIMEVAL 1 #else // Mac OS 9 # ifndef __MWERKS__ # define inline # endif #define OGL_RUNTIME_LOAD // avoids corruption of OpenGL /* Define to 1 if the system has the type `struct timespec'. */ #define HAVE_STRUCT_TIMESPEC 0 /* Define to 1 if the system has the type `struct timeval'. */ #define HAVE_STRUCT_TIMEVAL 0 #endif // OS 9/X #define SDL_INPUT 1 dxx-rebirth-0.58.1-d1x/arch/carbon/descent.r000077500000000000000000000106501217717257200205500ustar00rootroot00000000000000#include "Processes.r" resource 'SIZE' (-1) { reserved, acceptSuspendResumeEvents, reserved, canBackground, doesActivateOnFGSwitch, backgroundAndForeground, getFrontClicks, ignoreAppDiedEvents, is32BitCompatible, isHighLevelEventAware, onlyLocalHLEvents, notStationeryAware, useTextEditServices, reserved, reserved, reserved, 50000*1024, // 50 megs maximum 30000*1024 // 30 megs minimum }; data 'DLOG' (1000) { $"0072 0040 00EA 01B3 0001 0100 0000 0000 0000 03E8 0C43 6F6D 6D61 6E64 204C 696E" /* .r.@.ê.³...........è.Command Lin */ $"6500 280A" /* e.( */ }; data 'DLOG' (1001) { $"0072 0040 00DB 01AC 0001 0100 0000 0000 0000 03E9 0C45 7272 6F72 2057 696E 646F" /* .r.@.Û.¬...........é.Error Windo */ $"7700 280A" /* w.( */ }; data 'DLOG' (1002) { $"00B8 00BE 0147 01D8 0005 0100 0000 0000 0000 03EA 1643 6F6E 6669 726D 2044 6973" /* .¸.¾.G.Ø...........ê.Confirm Dis */ $"706C 6179 2043 6861 6E67 6510 280A" /* play Change.( */ }; data 'DITL' (1000) { $"0005 0000 0000 0052 0113 0066 0158 0402 4F4B 0000 0000 0052 00C2 0066 0107 0406" /* .......R...f.X..OK.....R.Â.f.... */ $"4361 6E63 656C 0000 0000 000F 0084 001F 0155 1000 0000 0000 0054 0019 0066 007D" /* Cancel.......„...U.......T...f.} */ $"050E 4F75 7470 7574 2074 6F20 6669 6C65 0000 0000 000F 0018 001F 007F 080D 436F" /* ..Output to file..............Co */ $"6D6D 616E 6420 4C69 6E65 3A00 0000 0000 0030 0018 0040 0158 0702 0080" /* mmand Line:......0...@.X...€ */ }; data 'DITL' (1001) { $"0001 0000 0000 0046 0120 005A 015A 0402 4F4B 0000 0000 0010 000A 0038 0160 0800" /* .......F. .Z.Z..OK.......Â.8.`.. */ }; data 'DITL' (1002) { $"0002 0000 0000 006F 001E 0083 0058 0406 4361 6E63 656C 0000 0000 006E 00C0 0082" /* .......o...Æ’.X..Cancel.....n.À.‚ */ $"00FA 0402 4F4B 0000 0000 000E 000F 005F 010C 88B3 5468 6520 7365 7474 696E 6720" /* .ú..OK........._..ˆ³The setting */ $"666F 7220 796F 7572 206D 6F6E 6974 6F72 2068 6173 2062 6565 6E20 6368 616E 6765" /* for your monitor has been change */ $"642C 2061 6E64 2069 7420 6D61 7920 6E6F 7420 6265 2064 6973 706C 6179 6564 2063" /* d, and it may not be displayed c */ $"6F72 7265 6374 6C79 2E20 546F 2063 6F6E 6669 726D 2074 6865 2064 6973 706C 6179" /* orrectly. To confirm the display */ $"2069 7320 636F 7272 6563 742C 2063 6C69 636B 204F 4B2E 2054 6F20 7265 7475 726E" /* is correct, click OK. To return */ $"2074 6F20 7468 6520 6F72 6967 696E 616C 2073 6574 7469 6E67 2C20 636C 6963 6B20" /* to the original setting, click */ $"4361 6E63 656C 2E00" /* Cancel.. */ }; data 'MENU' (128, preload) { $"0080 0000 0000 0000 0000 FFFF FFFB 0114 0C41 626F 7574 2053 444C 2E2E 2E00 0000" /* .€........ÿÿÿû...About SDL...... */ $"0001 2D00 0000 0000" /* ..-..... */ }; data 'MENU' (129) { $"0081 0000 0000 0000 0000 FFFF FFFF 0C56 6964 656F 2044 7269 7665 7219 4472 6177" /* .Â........ÿÿÿÿ.Video Driver.Draw */ $"5370 726F 636B 6574 2028 4675 6C6C 7363 7265 656E 2900 0000 001E 546F 6F6C 426F" /* Sprocket (Fullscreen).....ToolBo */ $"7820 2028 4675 6C6C 7363 7265 656E 2F57 696E 646F 7765 6429 0000 0000 00" /* x (Fullscreen/Windowed)..... */ }; data 'CNTL' (128) { $"0000 0000 0010 0140 0000 0100 0064 0081 03F0 0000 0000 0D56 6964 656F 2044 7269" /* .......@.....d.Â.ð.....Video Dri */ $"7665 723A" /* ver: */ }; data 'TMPL' (128, "CLne") { $"0C43 6F6D 6D61 6E64 204C 696E 6550 5354 520C 5669 6465 6F20 4472 6976 6572 5053" /* .Command LinePSTR.Video DriverPS */ $"5452 0C53 6176 6520 546F 2046 696C 6542 4F4F 4C" /* TR.Save To FileBOOL */ }; dxx-rebirth-0.58.1-d1x/arch/carbon/messagebox.c000066400000000000000000000043031217717257200212340ustar00rootroot00000000000000/* * messagebox.c * d1x-rebirth * * Display an error or warning messagebox using the OS's window server. * */ #ifdef __APPLE__ #include #else #include #endif #include "window.h" #include "event.h" #include "messagebox.h" void display_mac_alert(char *message, int error) { window *wind; d_event event; int fullscreen; bool osX = FALSE; uint response; int16_t itemHit; // Handle Descent's windows properly if ((wind = window_get_front())) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_DEACTIVATED); if (grd_curscreen && (fullscreen = gr_check_fullscreen())) gr_toggle_fullscreen(); osX = ( Gestalt(gestaltSystemVersion, (long *) &response) == noErr) && (response >= 0x01000 ); ShowCursor(); if (osX) { #ifdef TARGET_API_MAC_CARBON DialogRef alert; CFStringRef error_text = CFSTR("Sorry, a critical error has occurred."); CFStringRef text = NULL; text = CFStringCreateWithCString(CFAllocatorGetDefault(), message, kCFStringEncodingMacRoman); if (!text) { if (wind) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); return; } if (CreateStandardAlert(error ? kAlertStopAlert : kAlertNoteAlert, error ? error_text : text, error ? text : NULL, 0, &alert) != noErr) { CFRelease(text); if (wind) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); return; } RunStandardAlert(alert, 0, &itemHit); CFRelease(text); #endif } else { // This #if guard removes both compiler warnings // and complications if we didn't link the (older) Mac OS X SDK that actually supports the following. #if !defined(MAC_OS_X_VERSION_MAX_ALLOWED) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4) Str255 error_text = "\pSorry, a critical error has occurred."; Str255 text; CopyCStringToPascal(message, text); StandardAlert(error ? kAlertStopAlert : kAlertNoteAlert, error ? error_text : text, error ? text : NULL, 0, &itemHit); #endif } if ((wind = window_get_front())) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); if (grd_curscreen && !error && fullscreen) gr_toggle_fullscreen(); } void msgbox_warning(char *message) { display_mac_alert(message, 0); } void msgbox_error(const char *message) { display_mac_alert(message, 1); } dxx-rebirth-0.58.1-d1x/arch/cocoa/000077500000000000000000000000001217717257200165535ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/cocoa/SDLMain.h000066400000000000000000000004631217717257200201560ustar00rootroot00000000000000/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import @interface SDLMain : NSObject @end dxx-rebirth-0.58.1-d1x/arch/cocoa/SDLMain.m000066400000000000000000000256751217717257200201770ustar00rootroot00000000000000/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #include "SDL.h" #include "SDLMain.h" #include /* for MAXPATHLEN */ #include /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 0 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; static NSString *getApplicationName(void) { const NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif @interface NSApplication (SDLApplication) @end @implementation NSApplication (SDLApplication) /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } @end /* The main class of the application, the application's delegate */ @implementation SDLMain /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) { chdir(parentdir); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } } #else static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [NSApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [NSApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif /* * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char *) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; /* Set the working directory to the .app's parent directory */ [self setupWorkingDirectory:gFinderLaunch]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end #ifdef main # undef main #endif /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } #if SDL_USE_NIB_FILE NSApplicationMain (argc, argv); #else CustomApplicationMain (argc, argv); #endif return 0; } dxx-rebirth-0.58.1-d1x/arch/cocoa/d1x-rebirth.icns000066400000000000000000001761401217717257200215730ustar00rootroot00000000000000icnsü`ics#Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿis32îÚ¨‚« ¯ÆËÍÍÎÍÉÚ¨ƒ åùôóîôå—«‚ K‹}ÊÿùÿõŸ«€ "/:N8!‡þÿó£« 1VR;=a=’ÿì–«=‚pJLbkJ1Óôž«*7NQab’–\û¢«19@SeabyM$hø¤«5?JUc…yD-i÷¤«1>JO€fd~_;“ú¡«#9DIeYp2"Õùœ« ,?o[\r1Œÿõ¢«€ 3LNd4(˜ÿÿó¢« !£Ý€ÿõ¢©ìÿý÷ö÷ìŸÏz~€~–˜—“¢Ò›  Ÿ ¡£«¬¨ª«Î›ƒ ˆŠŸ˜²•s  ?Œ®y‘µ²Ï®| €?žµ¬¶i‡­Ä©€ ;¿Üظš®‰qš¶v  ŒÐâÝÊ­­°~š‹x 2™ÁÓÒмÑÖ§nŒ™ŸFŒ¦¸ÃÁ·²Ã•s~ ƒŸEƒ‘¡¬·ÐØ¿z”Š .{‡”œÈ²¯Å©’„”†  h‚Œ•Ƭ¢¶~fš£w + x‹¾¤¦¼}l}Ÿž} € &€¤¤ÊŒj˜´°š  2P¦ªÃÀµœ„œƒ —©®¿À«‰|Çmqrt{}ƒˆˆ|r•Í“‚˜–€ˆÁ’„ g˜ f  d6 %k˜€fÝìÞëÉe!k˜aýÿøäÎÚ¼³rl˜ÌüÿþóáßÚγ;l˜UÔìúùøó÷òÔ®gl—mÁÖéôúúîñÇ®zl—k·ÆÙëúÿýéù{k˜N°¹ÌÜ÷îêëÖÊd l˜›²ÁÑñß×Û²3m˜H ®¼äÓÓâ´¬]m˜€ C³ÕÕøÈ˜^m˜ QuŽh2!"l”„ gÂdijh`a€_`Z‹s8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿICN#ÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþil32 gýó‰ö÷õêåéê†ëêòÿój‰ntŸ–¡Ÿ …¥¢–åöjŠôüø€üûûüü€ûú¯önŠ þÿøïòûÿÿõû€ÿùj©önˆ )°¦ËÖäðþþÝö€ÿü…¬ön† `:?Žâ„ÿý‹®ön„%+*.86}=)’úÿþ€ÿ÷ˆ¯önƒ,14542-gq(0%uùÿþÿÿù‹®ön‚#2:DD><::;zs04-mú€ÿ÷u¬ön.@WmeND@@A8q^40-2¢ÿ÷ûðh¬ön&/Esšˆ[IEAGFQ:Ee74ãúùì‚®ön€ '1Dk~YJN[PGc«;X](‡ÿÿ÷Нön€&*2=M]YNK‚p{kâ´Lel-"Bóþ舮ön€)*.39@FJL`YR`iŸ¸‹ƒD3(,Òÿü‰®ön"+06;?DJUŒ€]oXNuv@>8,!¯ÿýŠ®ön&/38=AGNW[`bfrSP¡L@8.žÿü‰­ön(/6;@ELQX]ah˜½}£DA:/›ÿüŠ®ön$.8ÛñøþþýøñäÙÎÄãÚ±¨¬Èn .®ïK€ ¬äïû€þûôëߨÏÔô¼ÃßÇ­0!-®ïK€JÍÛîú€þûöðîá×êõÀÖÓ¥n"-®ïK‹ÆÖèõüýüøöûø÷ôÿûÕÚÜ¥¦‘.!/®ïK§½Ðàëô÷÷öùöñïð÷ÿõëÅ«¦B-®ïK1¬³ÅÕãêïò÷ýøøóëãñëź¯¢¤T-®ïK<¨­»Ë×áèï"óøüýýûèãüͼ°¤¢^.®ïK<«ª·ÄÎÙàêñöý€ÿnùúöɾ³¦¦^,®ïK0§¥µ½ÉÑÛäíóýÿúûÿïÍ·¯©§M,®ïK𣬹ÂËÓÝæíþùëëùêÓÝØÚá©4-®ïK}¦¥³»ÆÎ×ÜðÿïáÜæÿóàܹ§Œ!,®ïK€@§¢ª¶ÀÆÌÒáýãÖÓÒùб«  d 0®ïK€ ‰£¨²¸ÃÕÐàýíÑÅÙèµ±­¢”(/®ïK-¥ª¬¬ÁâÓþÚÊâæó¯§¢¨Q.®ïKL¬£¤¿ïíÖµ¹ÜúÇ©¬£©m /®ïKƒN¥Íë§³ËÚúÔŸ¡£¥l/®ïK„1ƒÝЮòå÷üÏ ¥Q""#!.®ïK…C|¦¾¤ÀéÀ…[*"" !.®ïK‡':LC.!##!%"-®ïK‹€# "#$" -®îHŠ  " #"*®î`=ˆCD?+./.-,++*-,..,/«ýΕ‰™˜•ƒ”€•”Ál8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿich#Hÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþih32Û®ÿྑǹ°¥µ·¶¹‚º¹»„º¼âÿÿ¾`‘NX›—“›˜– ‚Ÿ žƒŸy©òÿÇM‘+ö‘ÿ•€ËÿÇN‘/úÿþòöŒÿü|qÈÿÇN‘.ýÿÿðèãîôÿöôƒÿøofÊÿÇN‘ÃÕâóÿ×ÍÜçþÿÿÐÒƒÿý‘uÉÿÇNO_O¡E4Rw©åÿúÿþÿûýƒÿý•ÇÿÇNŠ  (D™œ‹4#MŸå‚ÿþ‚ÿþ•~ÇÿÇN‰%'(&$85(\‘7('@œùÿÿþþ‚ÿøÇÿÇN‡#)+/201./5.‡q#.-(ìÿÿþþ€ÿúò’€ÇÿÇN†(+0557554570{ƒ7-2.,%lêÿÿþ€ÿþû”ÇÿÇN… (.4;@@><:9 =‚ F130-)dïÿþÿü‡rÉÿÇN„(2=CPVTLDA?<<>=4p•>673.'~úÿ€ýüêliÊÿÇN„(%*7EUlvo]MHD@@BCD5n€785+0JA­ÿûóùþòqlÊÿÇNƒ) %+8Jf‡—‹mTIEDDEFGFZ§H;7GqH+KëÿòøòâŠzÈÿÇN‚*$(.:LjŒžpWLJFBGIKJE®g:EŽF(&›þÿþúöÇÿÇN‚*!$)/9H^zˆ~eTMHMd\MKMnÕc>@}B/.Géÿþþ÷”ÇÿÇN‚*$'+07AM\eaUOLY¥|q‹UzõÐQ<5ƒd,.'¼ÿÿëß“}ÇÿÇN+&*-16BFILL^cPW[X\YÅ’Œ‡T872+fóÿÿý”ÇÿÇN+*)-157=>AFILN¤T]^][XNo•L?@>94,!Kàÿÿý”ÇÿÇN+*).269=?CFKN`na]ab`_]XM{žDC?93-";Ðÿÿý”~ÇÿÇN+*/047;=AEIMRSV]cedi{bURh³GB@93.#4Ìÿÿü“|ÇÿÇN+,.189>@CHLOTY]addb—Ù–[V¬¹BB@;5/%4Åÿÿü”ÇÿÇN+,,27;?BEJNQW[^bcp­ ˆ®¼Ÿ˜VEB@93-"?Êýþý”ÇÿÇN+++3<:?DGKOSW[]^|¶’W[Y¬ÉIEGA:4.&%NÖ÷ýý”ÇÿÇN+$+18:?BHKNSVZ\X¦{X]]V‚‰ADE?HQj€GdÝþÿý”ÇÿÇN++.3;?AFJLPTWW}´bZYYO„kR†’¤–c`R Žûÿþý–ÇÿÇN‚**,27<@EHKPQTR´ºTWVTKs¶À˜YVA*#"ÀÿÿüïÇÿÇN‚*'+047>AEHLNPO‡°ORRQKWÅ“>8423+UìÿþÿõiqÉÿÇN‚*)+09;?CECIMLOÁEMLIIšL>;<6,&œÿÿþÿþŒsÉÿÇNƒ)!-068:@E^\KKo©_GB>`žE:781+Nàÿÿþÿý’xÈÿÇN„(152:79KŠC=[¥S>q•Wg¢F8840,$(ªÿÿþþÿý•ÇÿÇN…,-026>ey°l8A>O«¦M596.+"‰Üø€þÿý•~ÇÿÇN…'*+-43v¤qV;>=Dm[15212! ƒïûþûýþÿü“|ÇÿÇN‡%(,-C„6.0294\Ä‚*2/-,#‡üÿþýþýþÿù}ÇÿÇN‡ !'ds,.>„ƒ}CeO(+*"7«ùÿÿþþÿ€þü”~ÇÿÇN‰pF'.zyDywQ$!+fÏÿÿ‚þ€ÿý”ÇÿÇN‹! 3A)%z©I.lÃûÿÿýÿÿþýþÿøþý”ÇÿÇN  LiŽ«×÷€ÿþÿÿ€þ ÿþûÿþ”€ÇÿÇN‘ ×çðþ€ÿþÿþ€ÿþ€ÿ þÿþù’yÈÿÇN‘"ó€ÿýýþþ…ÿ þþÿüøuÉÿÇN‘)øÿþ•}ÇÿÇO-öþýüŠýü•Çÿ½khgk•„–——––€—ƒ–‚„ÇÿÝ™‚ƒ„}vvw{ƒÅÿÿÒ¥§¨’§¦ªØ®ÿÙ®¶·°œ’‰”˜—˜Ÿ¢ £˜žœž¤¢¡¦¥¨Ùÿÿ®@7 8=UADDFC@^€`VRXQSZ^afhFõÿ¶6‘š¢ª›§¯¦²¶¤¬«§¤§µ®´µµ·O\Ñÿ¶7‘#³¨œ‰’¯·²¸ª¦¤¥°±½À»µ¯¤2SÌÿ¶7‘!°­—……†—¤Ã½·´œ¡»ÀËÊĸ˜'PÎÿ¶7#¥¦•ššuo‹¹¼¼‚‰ÅÂÓØÌÀ¦DYÍÿ¶7‹!:f¢¼½Ò“p|†‹‘©œ«³µ°·¾¾ÊÒµ´¶Q`Ëÿ¶7‰#'Qy‰˜¶÷øéágfms•®µ¯²¸¸º½ÅÆ¿¾¹M]Ìÿ¶7ˆ$SŒœ˜˜‰§œÑêŒnpfgv|§®¨¯³·¾ÂÄÀ£BcÌÿ¶7‡%2y¥«¯²¬£˜’’–ãÂnrrleb‰¦¬¬««ÂÐÔ¤•IgËÿ¶7…'7‹«®¹ÁÀ¹²¦™ÍÕˆtytopg„©©«¬¼ÑȤ©WdËÿ¶7„(8”«¸¿ÊÏÑÎǽ²§””Êä›wxvtqf‰ªª¯ÈÉ ²­?XÍÿ¶7„(.†­ÀÍÐØÚØÕÐǼ¯¥œ’‰ºÛŒ~{sma¶Ä·¤ ¡Ž)RÎÿ¶7ƒ)o¢µÆÓ×ÝÞÝÙÔÏ´«¡›”†¸Ï†~|r~¤›§²–ž›Ÿ‘0UÍÿ¶7‚*IŽ£³È×ÛáãâÜÖÏۦž˜’©ê™‚˜Í¤‡Ÿ©œœ…<[Ìÿ¶7‚*|–§¹ÌÖÚáåáÜÕÏÇ»­§¢›—šê®„—Ý”mjg‚ž¨£˜’A]Ìÿ¶7+C…”¨¹ÌÓ×ÜàÞØÔÏÄÁϾ¥œ Ä÷¨‡‹Ñstku£²¬¢“GbËÿ¶7+d‚“§¸ÈÐÔ×ÙØÕÒÌÓðÛÐ׬Ëÿþ«‰‚̯rvmk—´©‚B[Ìÿ¶7 -t”£´ÁÊÏÓ€ÒÏÈÓ̼«Í×äÿüÛÊÊÚŽywqf²§£ ?^Ìÿ¶7+Ay~‘ž­¸ÁÇÌÍÍÌÉÏ͸¶²­ª¯ÒôßÔÌ¢‚}zpjŸ¥©¨^jÊÿ¶7€,T|zŒ˜¤¯»½ÂÅÆÄÆìÔ·¸´¯©¤ž¾Ø‹‰„|pmx™¥©ªXbËÿ¶7€,Yvu„›¥®³¸¼½¿ÊÎÁ¹¹¶°°«£œÄÜ‹†€xqiv–©´­LaÌÿ¶7€, ^s}‹”£©¯²µ¸¶·¹º¹¶ÀÞ¹ Ÿ¼ì•‰ˆytjn–¨¬ªJ\Ìÿ¶7€, cuz}Š–œ¡¨ª¯²´¶·¹¶·æÿ௴óé‘ŠŠ„}vnrˆŸ¨§TbËÿ¶7€,[vszƒ‹‘—›¡¥©®°±´ºÇèàÑðóéÔ¥Ž‹Šxrkv‡•š¦alÊÿ¶7€,Ruo{‹†Œ”—œ¡¤©¬®°ÎóÔ«¬»îä”ŽŠ€|zqsu…‹š¨_nÊÿ¶7+=oowƒ‰Ž•—› ¤¨©­èΨ©«§ÐÈ–Œ”Ÿ¼Ð”t„“¤­[jÊÿ¶7+(hprw†ˆ‹“˜› £¤Í𴦥¤žÌ˯ÈÚàÞ·¨—n}™¡®bjÊÿ¶7+WoqxƒˆŽ•š›Ÿ¦êí«¤¡ž–º÷ûÓ¦¥“ugdj†–¦ LeËÿ¶7+;qoxy†Š‘——›žÐ롚• ö׎{x{ngx•ª´½¡&RÍÿ¶7‚*dlpu‚ƒ‡ŽŠ“—–¨öÀ—–’•⛇ƒ…plfy«À´³¥:PÍÿ¶7‚*;iqv€‚ˆ­«˜ÉòÝ­‘ŒŠ°à€~xrfn£«°­¨FUÍÿ¶7ƒ) S}{{ƒ|”׊¸èŸ‹¿×¦´ä™€yvqpj{–¦±´µ±P[Ìÿ¶7„( ]ttww~޹ÄÔ𷊈Ÿêî£}‚umiip”›ž±´¨M[Ìÿ¶7…')kqpq~ŠÊæÁ¤†„…–Àå¨}{zxxim‡””¡”–©´£DYÌÿ¶7…''dlqv˜æ‡suz„„ÉÿÌxwurqmi–±®­ ¤¢ž–Œ9YÍÿ¶7‡%PlrÅÌwq–ÖÙӬǦonofavŸ¶½º®´¶´±š£RaÌÿ¶7ˆ$;ZÅŸkÝÉšÔßâ²ljilб¼¸²¸º··½¿°®_jÊÿ¶7Š"@fc’¤zpzÚÿ¹er‡©Áž»¾º«¥¯µ¤«·ZfËÿ¶7Œ 7AKVs§š•¤¯·»¶¶¼ÆÅª´¹¦š¬°\fËÿ¶7‰ž¨±¢ž±¹´±¹Áǽ¾Ä·°®•—I[Ìÿ¶7‘Ž­µ´¥—¥²ÀÁÀÇÈÂŽ¯£¨––EVÍÿ¶7‘ž±¼À¯ ¨·¿ËÊÈÌÇǼ³°¡™¡S`Ëÿ¶8¨¯µ½²°µºÀÍÇÆÑÉÇÀ³§¨³®[kÊÿ­JLMLOgVQ\__ihmqtszvpibGSWXBgËÿ׈qrŽstpcZ^_`cgghhilnjiddY[]^awÇÿÿÕ§‘©ª«‚ª‚©ªª¬€«ª¬×®ÿÔ£‘¬¨˜™››š™š˜šœƒ™˜™Íÿÿ£,( )&€}õÿ¬'‘ ! #!"€ $aÑÿ¬(‘ "  ""%$"!%]Ìÿ¬(‘ $" !$%$%& $^Ìÿ¬(Ž)D:0$!#!#%)*$" "]Íÿ¬(‹ 7iœÄÓÚßÀ–‹zW/ !€" !$(""#![Íÿ¬(‰ GŠ¿ÍÕä€ÿüȤ¦¤Œa4!&$"!$%$$# \Íÿ¬(ˆ$,•ÖÝÕÐÆÁÙÐÈ÷ý¿ ¦–N#!$" !#%#!]Íÿ¬(†&^ÃçäããáÜÓËÄÄÔý礡¢žžŸw4 $&&![Íÿ¬(…' hÙðëîïíêäÞÕÎÊÇîô¿§©¤Ÿ¢¨ƒ1"&% ! [Íÿ¬(„(håìïô÷÷õñíæÞÖÏÆÉìúΩ§¦£¢¥Œ.!$%$!$]Íÿ¬(„YÒêðöúüüûøôïæÝÖÏÇÃåöÁ¯²¬£ž¤m'#"€! #]Íÿ¬(ƒ&¸æëôúý€þüøôìâÜÖÐÊÃàô¾¯­¦²ÏÌ`! !!$]Íÿ¬(‚ ‡ØàìöüþýúõïèáÛÕÑËØýÒµ²ÊìÑ̦,!! $]Íÿ¬(‚:ÃÔàìöüý€þýúöñëäÞÚÕÑÛþÛ»ÍøÂ¡ a "#$^Ìÿ¬(xÆÎßêõúý€þüú÷òðôìà×ßóÿؾÀï¿£¥£•4"$#^Ìÿ¬(+*§¾ÌÛæñøüýþýûùöøþüùùê÷ÿÿäÅ¿ìÔ¥¥ž¦R"%%_Ìÿ¬(+W¶¹ÊÖâëò÷ùúúù÷õú÷òí÷ûýÿÿûìí÷Ä©§£ n%#" %^Íÿ¬(€ uµ³ÅÐÛäëñôöùúôôòíêí÷ÿûñëÓ¸­« ¢…,"!!]Íÿ¬(€,б¯¿ÉÕÞèêîñóô÷ÿû÷øõñìåãôùÛÆ¿¸°«Ÿ£’6!"#]Íÿ¬(€§©·ÂÎ×àäèíðò÷ûû€úöõîãßðøÌÁ»±¨ š?!!$^Íÿ¬(€”£­²½ÆÐ×Ýäèíðóöúý€þÿøäáòþÑ¿¼²©£™E #_Ìÿ¬(€—¦©¯¾ÂÊÑØÞäéïóöúþÿþ€ÿóõÿûÏÀ½¶­¦ D #^Ìÿ¬(€‘©¥¬¶¿ÆÎÓÙßåíñôù…ÿïÛÇÀ¾³¨¢Ÿ›;!\Íÿ¬(€,†§ ¬¼ºÁÊÎÕÜáéíðøÿÿþöøþÿóÒÉÈ¿µ°­£§Œ.!]Íÿ¬(+n¦ž¦±¶¾ÄÌÐÖÜâéìõÿþòìíñýðÎÌÒÅÆÎâéÀy! #]Íÿ¬(+M¥ £¨¸¼¿ÇÌÒ×Þâèùÿùèæåãõüéëô÷ùáо¦` $\Íÿ¬(+$”  ¨¯¶»ÄÈÎÖ×ÝëÿÿòãßÜ×èÿÿïÓÓǬš˜£D"^Íÿ¬(+h¦ž¨ª¯¹¾ÃÈÐÒÖàøÿåÜÚÖÐÖýôÉ´®¨«ž ' !&`Ìÿ¬(‚*0£œ ¥²¶»ÂÄÄÎÑÑèÿìÐÒÑÌÎùѺ´µ¯ ›žR$&`Ìÿ¬(‚*o¡Ÿ¥°°´½ÅÛÛÒßöýöÞÌÆÆàöÀ³®°¨ ¢†# $`Ìÿ¬(ƒ)­¨«±­²ÁðÆÇöþÖÈæðØãüϳ°ª§¡¤ H$_Ìÿ¬(„(?œ¤¤¦§¯Çãåðÿ⻾ÁÕüÿÙ±²¯¥œž­[ $_Ìÿ¬(„(O¨¢ ¡®ÆñõáÓ¼·¹ËèûÖµ©«©¥ž§u# %_Ìÿ¬(…'O£ ©Ìÿ¿§©°ºÁìÿì­¥¦¤¡£§v#"%_Ìÿ¬(†&<‹¥¨îﬥËïôùëðØ¡žž™¡›Y$"!" $^Íÿ¬(ˆ$!nšíЛ·ùèÍòøøß¡Ÿ¦œ‚F!#""## $]Íÿ¬(‰#)p§žÍ×°©¹ïÿï©¡L'"# " ! $]Íÿ¬(‹!>`t„Š›šzV<% !"$$"!" $]Íÿ¬(1-"# "#$!#&$""^Íÿ¬(‘ $#"$""$$# ! "_Ìÿ¬(‘ ##  "$$#€$ "!""^Íÿ¬)‘!#! !#%"$(&%" ! "]Íÿ£4;<6 %%&%&$##$""#$$#'%(&ZÌÿÒ}fghdS€VUUTSTSTSRTSUUWUTTNmÈÿÿÖ©ªŽ«ª«’­¬­×h8mk ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿit32‡pÿÿÿÿÿÿûÿ„µ€zjyu}iJTfk|…~rszƒƒŠ‚~|ƒ‚€‚ƒ‚ˆ…ÿ€~~³€{j~xopcn€~~}xuzytnt}‡~ }}~~~€}wz~€ƒÿ€~yh³gbeš™––œš–”’Œ•›‹}€Œ˜˜‡—––—˜Ž—˜˜Š|€‚ÿ€€e´xÿüûþúýÿ ûúÿÿ÷öüÿþþÿþûþÿÿþþ‰ÿü°r€ÿ€€e´zþõì±ÿù²r}}ÿ€€g´yþüùþÿþý„þýý‹þýüþÿù±mvwÿ€€g´ }þþÿÿþþüýüöúÿ§þÿú±hswÿ€€g´ „þþý€þ÷öúíñüþÿ™þ‚ÿ„þÿø¬]ioÿ€€g´ ‡þÿÿ€þù÷öéâëùÿÿ•þ…ÿ„þÿï’J\`ÿ€€g´ˆþýü€þ ÿÿóÜÓâôøøý€ÿ€þÿÿ‡þÿÿþþƒÿþ‚ÿ‚þä@QPÿ€€g´ |þûûÿþýýüöíêìãÐÏéýùóûÿ…þÿÿýýþþ‰ÿ€þÿýí–LLCÿ€€g´pÿþþ€ÿýóñýþêÔ¿¨ÁÞÙÑãõýÿþÿÿþþÿÿ€þèÐàú†ÿþ‚ÿþÿÿ÷¦eVGÿ€€g´húóðóôøõêíüÿûô忲·½ÌÎÐè÷þÿþþ‚ÿö¨vºùŒÿþþÿù°mb[ÿ€€g´J´·¿ÇÎÔÜèðöüøéÑ¿ÈÝôìÖÎ×òÿþƒÿó­˜Ù€ÿþŠÿþÿù±pxuÿ€€g­ €#*[SZdoyˆ™¨¸ÊÜâÚÔÝóþÿÿþä×ëþÿÿþþÿþÿþöûÿþŠÿþÿù°o~ÿ€€g«#Hrk;C:>`V)#*1=H]u¨¿Òèöüüýÿÿûùüþÿÿþÿþþˆÿ‚þÿù°p}}ÿ€€g¨" $7@¬ý–I_`}ר€)&2FhŠ©ÄÚìøýÿ…þÿÿ€þˆÿ€þÿþÿù°q~ÿ€€g¥)  */31cÄ®z•²ÊÞÝÞ•*%$,FfеÙìøýÿÿƒþÿÿþ€ÿ€þˆÿþÿþÿù°r}|ÿ€€g¢ €#%&'$%&C¼ëßʪ]\ ìž@),-**#2_¹Ùîúÿÿ‚þÿÿþþÿ‚þ‰ÿþÿù°q|{ÿ€€g¡  &'"$(%(&WÁŽC>)0U¼í§N#)3/'&'%8_‘Àßóþÿÿþþÿÿ†þ‹ÿú²p}|ÿ€€gŸ  €$,##&)&%&()*((D0,58AZ­®O-.(+-*('!7iš·Õóþÿ‰þ‹ÿó¬r}|ÿ€€g€$&(%&-,'&(*+*,3-).€27=7jÞ½9!€+,*'')'"!>XƒÇôýþ€ÿ‡þˆÿüâ u€~ÿ€€gœ"&%$'))'(++)*+*+,.35€0 137>CK•ÞŒ,(.+€)')+)'!DÒðúüûþÿ…þ†ÿþýú÷ç¤s€~ÿ€€g›<!%$&'((')--,..0110/./00125767=A]ÇÂ@$1.,--+*)*('%GŠÇêôõûÿ†þ…ÿþðéúù®p€~ÿ€€g™. ##%&&(+,.-136;73356210/02498568F‡ã±:+20/001.€* (&($5z»âòûÿ…þ†ÿþïëþù¬q€~ÿ€€g˜%%$'))-/493025:7€2424€2#3478797J±ìo#3621010.-/.*(**&+l³áõü…þ†ÿþýüÿ÷«s~ÿ€€g— %%')*-0324753343432€354‚5#78:7?›ßr3=653120/.//-*+,)%&c¬Ýóýÿÿ„þƒÿýú€ÿù±s€ÿ€€g–!$%&(*,/233567€816776877667677887985\²Ç¯ŠC*464540..-*,.-*'  ]ªÜôýÿ„þƒÿ ýùýþÿù±p‚‚ÿ€€g• ##"'++-0246:=>=<;<;::98997788€9 :85UšÐâŸD4:86630//.,+/1,(#]­ßõý„þ€ÿ„þÿ÷¦annÿ€€g”#%"$*//168;=ADC€D B@@>=<;:9;€9€:€;#>927T¦ç¸]697543123.*,2,(*%!fµãøþÿþþ…ÿþþÿû¨^]Wÿ€€g“ #"$)/137;=BDGJ€KJGEDBA><;;<:;::<<€= >>=4-C•îÉT+77658:61.,.+'&+*'q½éù…ÿ þüüþýûøó÷ð¡^ZUÿ€€g“ "!%(.26:>@A5;“í±B/:87:<8321/-*&(.%.Ëïýÿÿþ€ÿýûõôýÿúïãâ̓MQNÿ€€g’!!$**,0ELQUZ^_^\ZUPMIFDBGI=>>ƒ=??A?@AA:A„Å›K7:8€7$56520-**+(:–Øöÿÿþÿûûüýúøþþü÷ïéуETVÿ€€g‘"!(.++2@G@BLSZafjkjic]XSOJICOQ„?@?ACCA€B!E;2xד:==:8657422./2-%(O«äúÿÿüò÷€ÿüýú€þýñAUXÿ€€g!! !'))+3:=AIS[dntwxytmg`XRMJFHGBƒABABD€C2EDEB0FÄÊS>G?88663132.&Cƒ†H/pÂíüÿùõüõìúùûûþüúþô™JVWÿ€€g( "!#&'*.49=ENXbmw€„…„xog^UOKHEBDBBABBABC4DCFFEC<<˜Òk:H@::87533.'-?tœ„lHFÕõþüýÿåÓãîûÿÿôêïè£^deÿ€€g'"!#%(),05([²çüþþÿðæâìùþýêØãè¦`ptÿ€€gŽ €"&*,.27?FMVamzˆ’˜™˜’‡{pe[SPKIG€EDEDEEDFGG‚H JLD^Ç´NAD><€;4;l¡”U,$#$(/…Ïôþ ý÷úüÿõåÖêõªdy~ÿ€€gŽ!!!"%*++/37>FNWcp‹•œžœ–Š~sh]VPLJ€GFGIGEEF€HIIHIIJIER©åŽBA@€=>^¦Å†=),/-'&R¬äûþþ‚ÿ ýõðåïö¦i}~ÿ€€g$!#"#*-*+/48=DMWcp~‹•œŸ›”Š€sg]WPLJII€G+JJIHGIIHJIKJIKKIGxå¶E>C@?;@›ÜŒ9%+/1.)'&(€Îôƒþ ýôúü÷õî¡j~}ÿ€€g!%%##(**,279=DMVanz‡‘—š—†|pd\UPM€K/JIHF<=HKJIJLLKLLMNMB{ã¤@?GDB:=‘Åj.21.--+()R®çû‚þ üøþþÿþó«q€€ÿ€€gŒ €"R#')+-168=CJR]hs~‰ˆ€ukaZTOMLKJKIJKSVHGMNLMNKMOOMHL¤ïŒ8]«Œ911/31,)''.ˆÒõþþÿ€þ ÿþþÿÿø°t~ÿ€€gŒX" !"%)++-048bqjyˆwM?K€PMWˆ´Íùø™?BFCCB<<|«d.€2 4.)0.&?›ßûÿÿþÿýêæï¬p~}ÿ€€g‹€#R$%'(*-/136:>DHMSZ`ehlmhc]YUQONOMMJIl ÅJi”£ŸsAMTNP{×úüÿÚ{FHGDCDB4V¨ƒ1/3120+)''&zËóþ ýÿùßÏÛê°pzzÿ€€g‹N%"#$&)*+-/246:=AEGLTX[^_^]ZWTQNNMNMNZ‚£ç÷¢ON^l°›bRQP¥ûüûÙ›fUOKHFH@-hÄ‚.24132€*' Y´êýÿþýýÿòÕÖêõ±p~~ÿ€€gŠ !#"$%(-,*-/3458;?ADHNRT€UTSQPNM6NNn‚q›‘cVPPKcÃÒhMm¡ëÿúë¤j\\TEAHI:M³¿W/65265+-0)$?›Þûÿÿ€þôèïüù°kutÿ€€gŠZ"#$&&),,+.03578:;>AEGLMMNONOMNNMMNMNQm`MYRMUUTM^Âí½¢—¬×ÿþ÷Ñ›iNLKF7->¤à69:5364-./)'*€Ïõÿþûûýÿ÷¨lyvÿ€€gŠ#$%&(*,+-.01368:<=?BCFIJ€KLLMLNONOOScUPQQTUVWVZx€Š%rd”ñÿÿðÜ˹®¾Ë°”¹øÆT3::7421.,+((g¾îþÿƒþÿøªo~ÿ€€gŠ )%$%'+.-,.02358::<>?B€EAGIJJKLLQPOOQP_USTVVWXXYZWWZZWSfŒ±î瓇¥³°¶Ë¹£eC=<:84331,*(''Q¬èÿÿƒþÿù¯r€~ÿ€€g‰ #*%%'(*€-O/224689;;=@ABDFGHIJKKLNOOMWqcTUVWXYZ[Z[ZYXWXYWY_ˆÞÏjXjc^e\OFA@?<:9532.,,)&'>™Ûøƒþÿÿø°r~ÿ€€g‰!$&$&))+./.0244689;<<;85770..*&&/ŠÓùÿƒþÿù°q~ÿ€€g‰/$#&()),10.135667:==ABBEGHIJLKQg†’ž‚XY[\]^_`_^^]\[ZWVXZVHlÑ¿\E€ID@>><97740.+)&+(^»çìùÿþÿù°q€€ÿ€€g‰ €&Z(*-//0257768:;=>?@@CEEFGJKMLO^››ZS_][]^_``abb``__^]\\ZVVWUPLê¨KDHGD@??=:64221-)&(&W²éýÿþÿ€þÿù°r|zÿ€€g‰ &%'),€/135€7L9:;<<>ABBDFGIJMMOPMJNUX[\]^_aabbdda``ddb_\ZWVUTTJcËÉY>HFB@@>=;7532/-+('"O­éûƒþÿù°r|{ÿ€€g‰/ "&%()+-.02445799;<<>>ABCCFHIKLOPQUUWXY[]_``bccd€e*ffkqmb[YWVUUTKlÒË_BGDCAAC?:7531/-+(&#Kªèþÿ‚þÿù¯q~~ÿ€€gˆ^*'#+10-/024568:;<<>@AACEGHIIKMPQRUVXY[]^`acddeefefmu|vg\YXWVXWNkÔéw?EEC@?@>:7531./.*&#J¨çþÿ‚þÿù°osnÿ€€gˆ7*#.;8-.146789;<<>??ABE€GJMMOQRSVWYZ\^^`bdef€e,fjr†™wg_[XVW\`YmÐìw:DFCA@>;97741-12+%#I§äüÿ‚þÿù²nqlÿ€€gˆ3*$(/3./38:88:€=>@BCCFHIJJMNPRTUVXZ[]^`abdef+hhu•»»m_][XYdij¢úÑ\>GECA@?<8:>80-11*'%H¥âüƒþÿù°r‚€ÿ€€gˆ. %)'()-./38:88:=>>?ABCCEHJKLMOQSUVWYZ\^_abbefg€f-i|ª×÷üÚ«e\[_kp™éñ™MEGEBABD@9;=71,23*''Gãýüýþÿù°q€€ÿ€€g‰ &-'(*,.02588:;=€?IACDDGHHKMNORTVWXZ[\^_aaeegiheb{ÅöçÏÌàùá¦u^`fãß”dPGGEBABEA<8521.0.)$&+U˜Þýþýþÿù°q~ÿ€€g‰h $/+*,-/02468;=>?@ABBDFHIJLLOQRSUXY\[]^``bfhhifkˆÅê¯upo{¶øû¼qd…ÔßtBOLFFDBAA?::9631/.,($'/b›Øúýÿÿýüþÿù°q~ÿ€€g‰_*)*-..136889;>?@CDDEHIIKMNOQSVWXZ\\]_`acgjigv«äÜSW`bdk˜âó½©ÌËzAGIGGEDBAA?;88630.,,(&#b­ãú÷÷ù€þÿù°q~ÿ€€g‰h('*+,/25:;:9<>>@EFEEHJKLNOPQSVWYZ[]]^``cgjrÆóÑyT^ecfmcYËûÿËe;97651-**/*"nÄñ÷ìòôûýþÿù°q€€ÿ€€g‰##.',,+.06??99<=>@CFEEGIJMNOQRSTWYZ\€]A_`cfs§éè±hP_b_adfd]Z˜øì:GOLJHFFEC?=<<89?<2,)(4.+¸êðéöôùüþÿù°q~ÿ€€g‰h)(+,*-.6C?78<>?@@CEFHHKMNPPRUVWXY[\\^_abh™íÕ…_Zca^^]_ac`^ŒáË[BQLKIIJGDA@>;969B8)($!+,6‰­Úð÷ùøýÿþÿù°q~ÿ€€g‰ "'()+-/5;867:=>?@CE€HPILNOPQTUVWXZ[\]^_`oÉïrR_c`_^\\]]^_Yh»Æ^AOLJJLLHDBA;3//11,??ABEGIIJKLMOQRTVWXYZ[[\]^~ìàh^a`^]\\]]\ZZUsÉ´VHNLIHIID?;7@BDEGIJKKNPQRTTVWXZ[[\]a˜ú¹m^]^\€[&\[[YTSŸàˆJQLID?=AHKFNƒ½²ªÅ¼¶Èˤd:"h¶Ýôý€þÿù°q~ÿ€€gŠ4$'*++.1235:BA=>@BCCGHHJLMOPQRTUVWY[[]^xÎÞo`_]\[YXYY€X/RS§Û}JSOGCWwŠ”¢±ËíÖ‘ƒm\M;+!,†Êðýýüýÿþÿþÿù°q~ÿ€€g‹1 !'())-00358=<<>@BBEFGHILLMNPPTUUVWYZ_h¤ó_b_ZYZYWV$XRO“ÇzN\`f‹ÂÕÌ·µÓã½l;3.($!%$D¡Õóýý€þüûþþú±q~ÿ€€g‹Y)'(*,//136:;;>@ABFGGHIIKLNOQRRTVWXZawÎï‚dc]YXWXWUTUUTPJ~¿•koŽÌêÉŒlYLZ`K:62..,**.-b¸Þ÷ý€þ ÿûôôòøµr~ÿ€€g‹))(),/01259<;=;8962331,(')%DŸßõý„þøëÓ’g~€ÿ€€gŒ(*((,2334568:=€@BDEGHHKOMNNOQQRTVZq¹îU[TTSTTS€Q#OOMKCsÔ×ÒÚŽ>;;964264.*(%(e»ìóû„þÿÿßtAjnÿ€€gŒ $())*./0€4%79;=?@ABCEEHGHJKMNNPPQSVYoÊÛhQSQRRQQPP€O MLBP­¯hihL>??=;:654220,)''$8Õöü„þ€ÿó‡C[Xÿ€€g'&'(+-.13468:?=;8653/--,'*.Wµêýÿ þÿÿþÿþÿú«cifÿ€€g#%&(*-./15::9;>@ABDCCDFGIMN€MLNPQRXšüËeBOPNMNNM€KJJCKž¬T=BA@=<;86:92/.,*'*+"pËö‚ÿþÿÿ€þÿúµmssÿ€€gŽ&&(*-/..3?@88;FMLKLMMPR[Ÿÿþ÷¢EAKMKJJI€GHAB¡ÃX3?=;;:66€;96762.,-,)&(`¹Úíýÿ‡þÿù°pvrÿ€€gO().76-.113579:;;?@:B•bHHNRXYn¼ÒxGMq¡“gE9;AFFE<;;97541/.+-/+*!6•ßöü‰þÿù°r‚ÿ€€g‘N #*/DD,'.7<747:;;>S‚¥—pP>@C8I˜Û¬N3>>:98653210-+,,+&%g·îÿÿ‰þÿù°r~}ÿ€€g‘'*3;0)-;A6158€:<=#g¡W39?DEFMQë6BGGC;Bq³Å³„K;N¦Ý–H6<>;88753202.++*((]›Áêÿÿ‰þÿù°r|{ÿ€€g’M'$'-/.583025788=.M‹e8=?>522/.,)''* 4s ¿ÇÔìúþÿþý…þÿù°q~~ÿ€€g” +*'(**-/€138>E@,Œ»“Š ¹¾ÎÌzDB@@A€@*BC@30jÚý£F9A=:66786210,+(&&("0z¯Èäîíñúþüýÿ…þÿù¯r~}ÿ€€g•'.'&),--.0129@@B “üÝ´¬”uoW=A?@@€C(GE4KÉÙS1@>;7475112,)**&&) +wÂãêïõüþÿüõúÿþ ÿÿþþÿù¯r}|ÿ€€g•#€*H..*+,0366349>Am˜xn¶~/7<96442231.161('+$&q¼çûöíôþÿÿý÷úú€þ ýþÿþþÿú²oxwÿ€€g—Z%/)(*()-/233:&„³d=624889:<:=><;<=:LžóàÀ–>+955321/02.)9I6%'!*o¹äõþüùüýþýþüýùûýþýþýþýþö°musÿ€€g—"(%%&)/€0 320€<.26877878:;<=<;;Ir¥æÿÔa-253€1.-./,(06,$.v»äöþÿþÿþýþûü€þúüþÿüûë¨qzxÿ€€g™2 &&%(,-,/56sŸg=4345447842//8>?B\‡†ªá‰11411/1/-,-,*€' #7Àçøþÿÿ‚þûüÿþÿýþýüýýïªpzyÿ€€gš%('')).66®_?6€3*5577..?K98ILUba–Éd'410/./.,**(&&( HÈêùÿÿ€þýýÿþý†þü÷ýÿø°ozyÿ€€g›?((&&2/#”«T30212594?|’Ž©¤n13<@C»i)2//-,,+)(&&'$%^¡Óíûþÿÿþÿÿýÿÿþþÿ‚þýúþÿù±q~ÿ€€g( #((*0g¶Š;(*-//24AœæÃ}–ÒËuN:0-G“l*.-*)(('&3+,6Mn›Â•o¡¨b2,+(),+'"$K³×îùþ€ÿƒþÿþÿ‚þ‚ÿ þþÿþÿù°q~ÿ€€g¡sM(€'$(>Rm›T,+,-670>x•z°B<7'(++'Hv¦Îèõü€ÿþ÷øÿÿˆþÿÿþÿÿþýþÿÿù°q~ÿ€€g¤1 ,*#').>CC/-/+()*)*0H·š–Ë‚*Cb‡ªÉâñúÿþÿþÿþþ€ÿ‚þýüýþÿöêü€þÿù°q~ÿ€€g©*%('()% 5XX[]XC'4Kf‚Ÿ»Óåòúþÿÿþÿÿþÿþþ‚ÿ‚þýüþýüúóý€þÿù°q~ÿ€€g­ &%,34FSTfz‘¨½Ñàîöû‚þÿ€þÿþþƒÿ‚þ€ÿþÿüúýþý€þÿù°q~ÿ€€g´0ytvŠ”ž­¾ÌÙåîöûþÿÿ€þÿÿ€þÿÿþÿþ‚ÿþþ€ÿþ€ÿþþýþÿþÿù°q~ÿ€€g´OÈÄÉÓ×Ýäëðõûýþÿÿˆþÿþþ„ÿþþ€ÿþþÿ„þüûÿÿù°r~ÿ€€g´fúõ÷øùû€þÿþþÿþý€þÿÿ€þ ÿÿþÿþþÿÿþþÿÿþ…ÿ„þûüúûù±qwqÿ€€g´_ôû„ÿûòöþþý†þˆÿþÿþþÿ…þÿûìíõ³g]Wÿ€€g´Sãþÿ‚þÿþüúûüüƒþÿÿþ†ÿþ†ÿþþýý‚þøñøø²jfaÿ€€g´Zôÿÿþÿÿþÿþý„þ”ÿþþýý€þ ýùùþÿù°otoÿ€€g´gþÿÿ€þÿÿþÿÿþþý…þ‘ÿ…þ üûýþÿù°q|{ÿ€€g´xþÿ‚þÿþüû‡þŽÿ†þ ýýþþÿù±qupÿ€€g´tþÿþ‚ÿ†þÿÿþŽÿ‡þ ûýþüÿù°r~ÿ€€g´uþÿ‚þÿ‰þÿþÿ‡þÿù°q~ÿ€€e´xþ³ÿú²q~ÿ€€g±{üø’ù‚øùù…øùøŒùô¯r~ÿ€uOM²NMp¼²°„±°°…±°±ƒ°¯„°²°’z€~ÿ€~‚±Œƒ`ntrqr‰qrrqqrqrz‚€ÿ}~~³€we~{~€ˆ€€€Ž€€~ÿ‡€~}}±|}tf~€|x{ˆ~€~Ž‘~}ÿùÿùÿùÿùÿÿÿÿÿÿûÿdµa>b^B9>.4'!%3B;./9A=26FGPP?AKNOLF@;55BEA<;FECJKPRGEFLUWQISZXYW]…ÿa``³b>c_MKE.*/$+;0175/02/')CWNJHFJJIEFI>6:@A9KK00<>EOQDGOGRRQTTUZ[WVXÿa`\³N>OLFSNEDBJVUA<:8FN>/.?VgdWXdjd^]`ZOLQXVVd_LKQTZ\ZY^\]cdfcbdf^POOÿabN´=J·¡˜™¢®›–š’—“Ž—¢›£¶±®´µ°±´²¨ ¢©­°¯ ž²¯¢’“©¶²¬®­³¶¬«¸²wDJIÿabN´0P»˜§±­›”¡§¡¦«¤¥©˜š²¿Áµ££¨¬°®«©±±›•£¡—¡®¶·ª¡ ±¸€µ ¹¶±·¼¹v089ÿabN´=LªŠ ±¯Ÿ”” ¥¡«´­²¶£Ÿ°¸¹¶¨™œª¯¦¢ª²¦˜ ±°¦¦«¯¸½¬®µ¶²°´°³±¯¶´q%(,ÿabN´=N¯œ¢¤¬¬–”Œ–Ÿž©´µ®¨Ÿ¤µºµ¯¦£¦©¨¡¢£¥ªª©¬±²±µ¹¹´¾¿¸²²´¯¶±£²¯i#.3ÿabN´=\Ê´¬§£ž‹’ƒ‡™š¦²·²°²«­·³±°¤Ÿ¥¦ Ÿ™ ­©¦§ª¬³»¼¼Äÿ¶«°±·°¦ª³§],0ÿabN´=bе°¥Ÿ—‹ƒ~„–¤§¬²º·©¨¸Àº®¦­¬¡ªªŸœ£±¶¯¬±¹¿¿¾Ç½¹¼¿·´µ¦¤«§ŠA#$ÿabN´=_Ä¡¥§¥žš“‰xr~’˜––¨¼°©ºÁ¿¾¼´«®´½´¦¤ ª²°´¸º½¼ÅÌÄÆËÆÁ¿´¯¶«v7ÿabN´=T¹‘Ÿ¶¬›’’Žˆ„ˆ‡{t|˜£˜»Ä¾ÃĹ­¶Á¹¨ª²Ÿš¤«´º½½ÀÉÐÒÐÅÄÊÄ¿½¶©˜ƒJÿabN´=K¹§´¾¯œŽŠ‡™¡‰vqcgwxn{Ÿ¸ÃÉÇ»¾Á¾´¥°¯‡n†¬½ÀÁ¿ÃÈÏÒÏÇËÍÆÂ¼°¨¢‹T*#ÿabN­€>PÃÁ¹°¬‚€›©•ˆ‡te`fzwsŒ©»Á»»½»½¶´£b6j±ÄÄ»»ÊÎÍÖØÕÒÌÇÁ½¸ª›•_1)#ÿabN©H O¡¦šœ—””œ¤¤tkn{ }gl´À¸·¸¼»¶¤hRˆ¹Âú»ÉÌÊÕÞÛÒÍËÆÄ¼³§¢a/76ÿabN¦K "(.9DJLL`‹Š}ŠŽ‹ž ©›v~‘“˜²«kq¶»±°¶·¬«¢¢´¼½¼½ÂÄÇËÏÓØÑËÄÁÁ¸¶¸¨a,<ÿabNŸ .BVpƒƒœ £¯Ú÷ÿ÷€ÿ#þþÿê§ploecjcbkry}{Š¥®§¥ºÃµ¬¬³·´¶¼¾»¹¼½¾ÅÉÉÎÏÌÆ¾·¸¿¹º¶n499ÿabNT 6Ocr—Œƒ‡‰„‡ˆ•ÅòÿýõíÞäúÿ讆~tqpe_^aefpƒ“ž¨¨®´°±²±¯²·º¹·¶·¹¹¸º¿ÄÂÁÃÆÊÈÊǾ¼¿À²d/98ÿabNœU2Puˆ‹‡•“…Š‹‡†‡‡ˆ“ÇøÞ¸¸©¹Þûÿ÷Â…u|ifigb`gv~‰›ž¡¨©¬°¬¥¬¶°«°³³µµ´·ÀÄÁ¾»»¿¾Âý¾¿¹¥b188ÿabNšA *Ee…••‘Ž–›‘ŒŒ‹¡Ì§ˆ––˜´Ýêúó¬zwvnr{skidego|‹Œ…‰›°­¤¬²©¡©±²µ€¶»¾ÁÀ½À¾½ÃÀ¼¼º¨]5;=ÿabN™X!?_{””˜ ¢——ª¥–‘‘“•‘Ÿ¥‘‹‘‰š¾Ðàÿí«tkoswqmlmkc_cpthg…«¶°«ª¬«¬±³³¶´µ¶·½ÁÃÈÊÈÆ¾¹»¹›xO8FFÿabN˜ +P}•œž¤§¥œ¤¢€œD˜•“–¡Ÿ“’‘–§¹Ëîÿá•opollkintqgdcejo}™°²£œ¨±­ª¯²­ž¨¶·¸ÁÇËÐÍÆ¾°«Ÿ’ƒQ5GCÿabN— 7]…›š˜ ¤£¥¡¢ª¬§¨ª¯®ª¥›™™˜€”;“”‘š¹ãÿó«urrppqpmosljhbemxˆŸªŸ“¢¯¥ ©´©’œ´»¾ÅÎÏÐÒͽŸ†€ Ÿ^9KGÿabN•!@lŽ™™œŸ¡¥©®±±·¼½Á¾¹´´³¥¡›—€–;›—ŽŒ“¸ðÿé ywtsuy{slnnkjhebfuŠ›ž­°¦¡ª²®££°»ÄÌÏÏÓÖÓ½†’½¨\:MKÿabN”]$Fu– §«¬³¹ÁÈ¿¸º¾Â¾¶°¯¯ª«£›š˜›š’‘™ºöýÑ‘ƒ~wwvwxtqvwmkopjacs‡“ ­«¨­±ªª±°±²»ÊÉÍÖÖÒÀ¡œ£µ¤a9DDÿabN“$'L|™ ª¬­´ºÀÀÁÅÀ¼»»º¹·µ²±¯®©¤¢Ÿ™—€•6¨èÿÔ¬¡ˆxxwvwuswxplqxrf_bs„“¦§¢¨©££±²°²´ÂÉÔÙÐȯ’žœ¥°|EFDÿabN“'N~œŸ£¬±°°·»¿¿¾À€ÅHÃÁÀ¾¼º¶±¯©¥¢Ÿœ—–”’¼óþïÜ«~x{y}~vssqmrzzsibeo…ž©¦œ ¨©®ª¬¯¯ÁÎÙ˸¬™–¦©¯¼BIJÿabN’_(R™œœªµ²²¹¼¿ÃÇÊÊËÍÎÎÍÊÉÅÁ¾¹¶³­¦£ ž›˜”‘Œ‘¶âõÿ籓†}}yusrsqozƒvjgcn‡Ÿ§¥ª­ª¨©¬¦­ÇÚÔªš›ª¹·µ²§^(69ÿabN$MŸœ¡²¼¹¹ÂÆÉÌÑ€ÓKÔÔÒÐÍÌÉÅÀ¼¸µ¯ª§¤¡ž›——“ŒŠ—±áÿóÉ•|{yxvz}tlrwjmjer‹Ÿ¯°£¤¯³´»ÄÕà⢤°·¸´¬˜R%"ÿabN !Gy–š¢±ÂÃÀÄÉÎÐÒÖÖ€×JÖÔÓÏÎÌÈÃÀ¼·´¯«§¥¢žš˜–’Œ†Š¦ßÿô³~{}zzƒ‰‚xsqtsjirvpvŽ£¢ž¯À»ÀÒÖÕǪª¬«Ÿ•œŸ¢–R!& ÿabNb m‡Ž’—©¶±·ÃÇÐÖרÚÛÞáãä€ãJáßÜÙ×ÖÓÐÍÊÆÀ½º¶²®ª§¤¡›—•”—žš¾üíµ•Ž‡„„ƒ„‹™Å÷qjisvy‡”¤©¤­®¦¡¤ŸŸ“ƒ|Œ•Z%48ÿabN‹f+X}‡Ž“±´°¸ÃÉÎÔרÙÛÞáãåääãáÞÝÚØÕÔÑÎÊÆÂ¿¾»µ°«¨¦£ ›–•——–•´îÿ᥌ˆ„†Š–¼çþØ“utzsjfcg{‹”¡¤ ¯­¥¤ ˜“Œ‡—R"11ÿabN‹f@nˆ“§·°°¼ÅÊÏÓÕ×ÙÛÞáâääããàÞÝÛØÖÓÐÎËÈľ½¹¶²­¨§¤¡›™˜™š˜–¡Òÿî§ŠŒ‰ŠŠ¢åÿØ‘motzxnjfap‡˜ “ ©¢¢Ÿ™š’N01ÿabNŠg*W{Œ—•–¤«¬³¿ÉÌÎÓ×רÚÜßáääâàÞÝÝÙ×ÕÓÐÎËÉÄ¿»¶¬§ª¬©¥¢ žšš–™Ðÿà‰‘Ž‹„™âþÀˆztqssnqnbfsƒ›¡¦¥¥¢šŸ›—™b299ÿabNŠ>k€…Ž‘•¢¨«³¾ÈÌÏÒÕÖÖØÛÝà€áKßÞÝÚ×ÕÔÒÐÎËÈÿ»·¼¿­¥©§¤¢¡žœ›šžºîþÖ™‰Ž‰„‰¾úÕ{wtxxponfam…—¡­­¯«ª¤£¤žŽbLLÿabN†k /c}smopsuz~€„‰‹Œ’”–™›œž ¢¤¥§©ª¬¯¯°²²³³²³µ¶·¸»½»·¼ÖùÿûûúüÿÿñÕ½ºÏïÿùðÖ¥ŽŒŠˆ‹”Œƒ{xvr{zndk|Œ—š ¥œ› ­­vIVWÿabN†k ,`{zwstuvz}~ƒ‡‰“•–˜›Ÿ¡¡¤¥¦©«¬®¯°±±°±²³µ¹»¼½¿ÇÝöýêÚÚÙæüÿÿûÞÓçûóͱ§”ŒŽŒŠ‰Œ‰‚}yussqlfq‚…wƒ‘•˜™“•¤´¯{ORMÿabN†k )Ysnpvutvz|……‡Œ‘–˜—˜œžŸŸ¢£¤¦©«¬­¯®¯¯±²²¶»¿ÀÆÒëÿùݾ²³¹Êßñþÿüùüå½™‹‹Š‰ŠŠ„|xvsqrngku|{†”‘”¡¢««uLVUÿabN‡j $QtnfrsouzˆŒ†…Š–™–—™š ¢¢£¤¦©ª«¬­®¯°°±´·Â×éöÿóϲ¬°²¸¾¼ÆéýÿþÞ¨’”“‘Œˆ‡ˆ…~~ysmnzngr}‰ŽˆŒ—£¥¦qI[ZÿabN‡K{wjutosv‚‘‘„‚‡‰Š’€•——š€ ¢¥§¨©ª€­B®¯°´¼Òôÿþñέª¬­¯´¹¶±Êöÿó¼’’—•“‘Ž‹‡…„„~Šxnjivds‡zˆ‹‡Š‹™°© sMVQÿabN‡jCspjurnpr‚—Ž~†ˆ‰‹“•–˜˜šžžŸ¡¤¦§¨©ª«¬¬¯±³ÆìÿöàDZ­­«ªª®´·´¾èÿç«”š–”“”“‘‹‡„‚€|ƒ‘ƒswrgvqau‚l|Œ‘’‹–°¸«œvQXRÿabN‡j7_hglnnpr}‰ƒ}„‡‰‹Ž’–——˜˜›ž ¡£¤§¨©ªª«¬¯²ÉúýÞ¶®­­«ªª©«­¯¯³Ïûè©’™–””˜œ–Œ‡‚~yy…ˆ—·«šœgxs€•“•” ³®¥rHTVÿabN‡-Siklqpptwy|~€„‰ˆˆŒŽ‘€”P•—™›ž¡¡¢¤§¨©©ªª«³Öÿý׫¬­«©¨©««ª©©­Îûç«•—”’’•™’†‡˜¥¢¢³¾Çèÿøß‹ju‚{‡˜’”˜¢¤¬°°t "Jfggjlmp|‚|{|{~‚„„…ˆ‹¨««ÌÄ•›¥¥¯¾äÿúíìøÙ¢Œ‹‘“’‘Ž“¦Òþá“|„€‚#~{~xrosvqljgiv…|{˜¨¥©§§³´¯ª¯±©˜e7/'ÿabNd1Vfhqy~sttw|z|~ƒ…‡ˆ€“ÙêáÞ»–“›©±¾ÜÿöË«¨Äìç¶‘ˆ‡ŠŽŽ¥Öÿﲇ„„‚‚€|zyuurlu~ulhem|ކœ­²³³²°³¹·¼Ãº¥j994ÿabNŽ@?^irŠpiqˆ}y{ƒ…„s°ùâ´–‹’›§³ÓøøÀŒŠ§Øïײž“Љ‹¦Þÿí³‰ˆ†€€}yxrmuwqifkq|‘˜‘œ¬±²µ¶µ²¸³€¶®q42/ÿabNŽ %Ienr|„ynt‰}vz~Mn·í¥~‚…ˆ•©ÀìÿÎ‡Ž‹…Áóûíͪ™ªàÿß«Šƒ‰|{yvvzvmpunljkwxv‡—¢§¡¥²·¶±´³²«¯°o74.ÿabNb.Tgefouwwˆ{ux|€~~†x›Ø¶ˆˆ‹‡“¡·çÿð¦†ŒŽŒ…‹®Öòÿé×êÿ䟆‡„‚}Š…xyyuvqkpsidikprkwš§ª—–®¶°®³³«¢¨¥c372ÿabN"7Zgcckstuxwuwxz{‘’†¶äµž¦°ÉÜèÿÿÏ’€Š€‹Œˆ„‰°ô€ÿ/󸊈‡{}ŒŽ}x|wrpljlmigljfqty€¢§›”£®©­±±¨¤§g130ÿabN ?^hpulkmlruuwvy‚‘™‘ÝéÝæô€ÿBõÚ¦‰‡‡ˆ‰‹‹ŒŽ‡z‰Èüÿ󖋉ƒ}~€ƒvxxpnlggjlkpxqr‹’‰Œœ™˜š™¡¥¶¼¸¯¨®¯n63/ÿabN‘ Bbxylhmsurqtvy‡“–‹“Û€ÿFõÜÈĶ—‰‡†‡‡‰‹’¡«œ³÷÷¼Š‹…~{~wxyqmnmjijgjw|ˆ‰’‘¡©ŠŒš£©ºÆÆ´«°¥d24/ÿabN’_#Felosszumnnv~„’НðúðÖ±”‹‰†€„„‰Œ„‡Š‘‡‘ÑðÜÚõ̇}†…zywx}{uv}|pktrdn’‘¥†Š–Ÿ«©‡¡¥£©¸Â¯ ¯£_*,'ÿabN“%D_vzonplmsw{}}„”Û÷Ʀ’€} „ƒ‡‹‚ƒ†…‰µ÷€ÿ2íw}}zyxusu}vn‚lgkou•ž¨£”–œ¡¡«›“—˜˜ ¥¥˜¡—Y)(&ÿabN”$Egrhdiin{{wz} óä—yvz}€~‚‚ƒ„€†8ªìÿýÿùʆy|yvxyrqtvqlvrb]bz–ž­³©¤¨­©¨ˆ’¤«ˆ›ž˜›’‡Q)22ÿabN•\"@\hheemsttz†™Ê÷Ñ›€xzyyx~~vwy€ˆŒŽ›Íÿüøü×—{zxvvyxqorrnkmnd^e{˜¬°µº·®±µ²°²”‘¯¸§Ÿ«©¢œ–’’ˆ†U)/+ÿabN–[ 8Vhjgikln{ˆ§ë÷Å¡„{{z|}}‰”’—­¬¥ž«ÁØåûû†|xvttuurnmlkjie`m„š®´³¾²¨¬¸¬²¼µ²º·¬µ°¯«©™‰•›™]),&ÿabN—Z 0Ndkihhm€Ž«òõ¯ˆywxz€ˆ½ÜâìöìÕ«›š°ßøÄ‡{vsrponmkjhhfacqŒ ¨´·³¼µ­±¹ œ°¸¾¾¼²¯´¸¶©šŽ›­¬k4;:ÿabN˜Y'BZhifgx¦×þã“onrtuy‡ÅôÿÿåëÿýÖº§Ž…«ïÇvsnljikllhc`bj{“§°°³´³ºÇļ»¶°š¨½¼¶°µ¯¹¼­—–¢§·³uFOJÿabN™+5M`haj½üñ¯||zrurs—ñÿðË•ŸÅñÿùåË»ÈôÐ~otkhk€m h_^dt‰Ÿ¯²±´³¸¹¯³¹½¿Æ½¢®¹¸°²·´º¿·¯€®¯©sIUOÿabN›V &=R^_¨ÿò•n~olºåÿï´t{™ÃÙçüú÷øü×’ytnrwpjjdbp‚—­¹¹´²º¾¿º¬¢¤­¶¾Âü·¹³´¼ºÂȽ¶·¸§©ªwDPPÿabN› *AKiµìµtkkjn§×êódžvrw–¨è€ÿ4úÓ¢…nktwhbmv€“¥³ºº¼À»Äŧ¦º¶¨¥°º´¶º¾¾¹¸ÁÀ¾Âŵ©±­°³{AKOÿabNžS+9RˆŽqhghv­µ¢±–sosw~}¤æüýÿýÛ™wgafnmr‚’ ­¹ÁÄ¿»À¾¿Á«­ÁĹ·¼³¨¬´­°¸ºÀ¾ºº°¤‘©»²°uAKMÿabN #2ET_eip¨µ€{€wnptquˆ¢Ïò€ÿ3é“lfhr}†™¦´»º¹Å̾½¸À¾º¾ÂÁź¡§³£Š•³²ª³¶ ‡¥£±¹¸²t@JJÿabN¡P +9EPWv‡qnzxqtokisˆ¤ÀáàÆ§~ux}Š˜¡§°º·²µÃǶº¼°¸Á½½ÃÊÊ·“Œ¦¦”¥µ¨˜––ŠŽ³·µ°¼ºyAJJÿabN¤M '1:DLQY]`cagmmt}†‘…†‰“œ¤­¯°¬®µ¯²¾ÈÁ°¶»µ¼ÁÁÃÄÈÊ㑦¸¿ÆÂ¸§‹‰’™°¿¹±º¶u?JIÿabN§J #)-047:Y{x{„Œ‰’¡¡›¤®¬«­±±²³·¿¾¸°°»»¸»½ÀÄÈËÌŲ°ºÄ¿Áż£¢¦¤­± ¡´°tCKIÿabNªG E‰…‹š£¨©¬°­®ª¦Ÿ¥¬¶¼»¼¼¶¨›®¼²·½»¿ÅÇÈÅÀº¾Äƺ±¸·¶¶µ·¤š“›´«j8A?ÿabN®€>@—•¡©­¬³³¯®©ž–“¦´½¼·µ¶ºµ¹¹³»»¿ÊÄÁÇ·¯·¼Ãü·¸­²®¯¸¯ž‘–—™W)2.ÿabN´=8˜¥¨±°±²ÀµˆŠš“”¥²±µ¶¯¬¯ºÈǼ»ÀÀÄÏÎÃÁ²¯´¸ÂÃÁ¼·°£› ­¬¡ž……a'ÿabN´=0‚˜¦«¦ª´¹½°šŸ¢•Žœ«§¨²·½½¼¿½¾¿¿ÄËÏÍÅ¿½ÀÃÉÆÀÀ½µ«˜—©ª¤š‹‰‘“c0("ÿabN´=4›¤©¬±´»µ¦¯»±Ÿ““ž¨¬¯·ÅÌþ½¾ÂÃÀÄÈÇÉÉÇÅËÍ¿³¸»µ«£¦±¯ —•¦¥e32.ÿabN´=<˜ž¤±µ¶¹¹¸¼½±¢—™™Ÿ¬«©­·¾ÁÉÍÉÈÄÃÍÔËÄÅËÊÈÉŵ´µ°¨¯³¨Ÿ–—£¤¦t553ÿabN´=C¥¥°±¯»½»Á½­˜—¥¢¦±«®¼´°¿ÉÊÍÎËÉËÐÌÂÅÊÁ¾ÇÌǵ¬°¯ª«±¤›“šš˜¡£l72(ÿabN´=C§¨¬©«º»½Á¿½·§¢°­¡­·¹Á»¸ÆÎËËÌÊÄÁÅËËÈÇÂÄËÅ»¸²¶±¯®ª£™‘˜š˜¢žiDJCÿabN´=F®§¥«±¶¹¼¼½¹²«§±³¬°º¹º»ÀÉÌÉÃÆÈÄÅËÒ×ÏÅÃÈÊÃÀ½»»µ°«¨£¥¦ªª¨¬¥qDPOÿabN´=I³¯¯³¶´º¾¿À»·µ²·¹¹»¾¾¼¾¾ÈÕÔÊÄÇÊÍÑÓÛÖÅÊÏÉÍÌÄÁ¹­¨¬²¯±¿ÇÀº»´uCQNÿabO³0 N´«±¯©¨°¹º¶µ´²¯³¹º¹¹¸¶º»ÀÌÏÈÃÂÄÅÅÆÑÐÁÅÌÆÅÀ¸¹´¦“˜€« ·ÁÁ¾´«uIWUÿaaZµ;)P€}|qeelqswwvwuu{}|~}|‰ˆ„‹“†…ˆŒŽ‘Œ†‡ˆ…‚€|y^OfonqrptrjVGMIÿa`bj²k>mgRRQF;9>:.3KKC>@EFKRQMMQYVMT_\WYX\ba]\XUWRNMMNK7(9:47/7C>>DA<ÿ_€`²a&b\TZVD4ERKBGURMJQYXX^_\Z\bb_]^_cedfilea€c]WVXVSN10CLHKGJQOLORPÿea€_±^>_ZRUQ?-AQJINOIJNSXYXZ]\Z]_``^Z\bffgfib]`cc[UTVUQN43EKLMKKNNOQVXÿùÿùÿùÿùÿÿÿÿÿÿûÿO·M.?*+/--0101.,-/.+*+//,.-,0/-+*+,.022.++,,),-,,++€- +()*-,.,(()…ÿMLLµM<=')//-00-00,+..,.12-),..0/.,--,-00.-/*)01/.,)(--(-**+)**()*)(ÿMLI?´>4)-,,+,,),-+,*'+.1/)%*,,**)+,+*+,,'%,.+*&&,-*)*'€)*,)),,+ÿMM>´=&! ""! ! "" "! "! #" !" !&,+)ÿMM>´=$"! #$ !"!#% "$ ""!!""*/,+ÿMM>´=## ! !"!!  ! "$"$#" !%&"##!!"! !!)1/-ÿMM>´= "!  !  ! !"!##""$%%"''$!!##(1-+ÿMM>´%$"  "#! "€ #%#%('%  # €+1,)ÿMM>´=&""!'&"! !  !!! "&(%$' "%# !!(2-)ÿMM>´# €2&#!%$""# "%# ""##$%#%& #'(%#"#(3-,ÿMM>´$!#'% $&  $ %€ "$%%&(&'##)&##! *1/.ÿMM>µ<! "! "&% #"# #$&%%&&$#"%+)&  %,-.ÿMM>¬E 31+$$"!!#" !"#! #%""((&(*(%$$!  %,.+ÿMM>©H!'-358DVUMGEA93-*%!%$"$! %&!!#%!!('$+0-&!#"&$#!'-*'ÿMM>¦? !,:HVcq|„‰’›š‘Ї€tj`QE=0 $ $%"## !!" #"!$%$%&(,)€&%!#"!'.)&ÿMM>£N %8Max“©»ÈÔÝãèéèíëáÏ·°¬¢™Ž‚r_M9-' !" ! ##! !""$$"&+&!"!!"'+)'ÿMM>¡  5Mj‡›­Éáòˆÿ8ï«­«¥¬±£™x^H4($#"#!!#$"!""!#!$&"%%*$%# "'()&ÿMM>Ÿ#=^Ÿ¸ÆÅÈÔØÜçõ†ÿ8ýã´¡£šœ§¤¤ªª…iM8*!% !#&'%$$#"#"!$&&((&&%#"%""%&*)'ÿMM>#?e­ÁÑÓÉÁÀÀ¼ÀÅÓðþÿÿþýýÿâ´¤Ÿ¡•‘• §¨£‘qO8*$#  %((&$€" "$"#$%&$'&"#%$$'+*(ÿMM>œ š 0W†³ÑÛ×ÒÎÍÌÏÒËÇÆÆÅ¿×óáÆÌËÒê€ÿþá·§¥Ÿ ©£›—–œ¥­¤‰b='!"!!%'$!#$€!!!"#"$!!&#"! %-,+ÿMM>™ "FwªÌÛÛ×ÕÙÚÔÔÚØÏÌÉËËÅÄÑàȽÿ¼Õú€ÿ&þâ°œž¢¥ šžœ“–£«žvL2,)&%%&$##"!"  !!"#& #!"!%-*(ÿMM>˜.Y“ÆÝßÞÜÛÝàÞÚØÙÙÔÓÑÏÌÉÊÐЀÃ;ÁÄÌáôýÿÿûϤŸ œ›™—Ÿ¨¢–•¨ªbB3+#!%&""! "!!$$'&## &.*(ÿMM>–,;n©ÓãáÞàááâàßááÝÜÜßÝÙÖÎÌËÈÅÆÅÇÈÆÈØòÿÿýÜ­££€¡+ œŸ¤ž™—”¡­žuN5(!#$  !""$''$%%"")*(&ÿMM>•\ E»ÞäàáããäæèææèéçåæäáßÝÔÒÎÉÈÆÇÌÉÁÁÏìÿÿùÙ²§¥¤§«¬¢œžŸ›™˜•š¨§„U6(%$ #&''&#&(#&$'*'$ÿMM>”] "LŠÆäæâãçèèëëííìêééèçãßÜÛØÙÓÏÌÉÉÌÌÅÅÕîÿÿô×À®§¨§©¨¢¡§¨žš¡¡˜•¤­ŽZ8*" !%""%&)&!"$%,*'ÿMM>“I &R’ÌååäèéêíïðïððïíìêéçäâßÝÜÛ×ÔÑÐÎÊÉÈÈÍâýÿ÷êá«©¦§¦¤£¦©¡¢¨¤”£±“\9&€ #!&.''# #&%('ÿMM>’_ &U—ÏæääèëíîðòññòññðïîìëéçäãáÝÜØÔÒÑÍÈÇÆÃÉèþÿÿû佬«ª¯±¦¡£¡ž¢©«¥š•¤°”_9%! "#$-0# '($&$ÿMM>‘` "R—ÒæãâèìíðñòôõõöõõôóòðïîìèçäáßÚÖÒÐÏÌÉÆÃÀËäõþÿûä̼°®°ª¤¢¢£ Ÿ¨±©˜£¯’]5$! !! $(( "*%!!)/*'ÿMM>JÏæãâæëïðòóõ÷€ø€÷JöõóòñïìèåãàÜØÖÕÒÑÎÉÈÇÃÅÑçüÿþôÖ¶¬«ª¨§«¯¤›¡®ª›¤³‘V6)""$"()#(%#)2.-ÿMM>B‰Éâàâæëñóóô÷ùø€ú€ùJø÷õóòðîêçåâàÝÚØÖÕÐÌÊÉÅÀ¾Ëäúÿÿ齬­¬¬²¹´©£ §¤™š ¤±³‡Q0!%"#'%)(!##!"")/,,ÿMM>7zÂàÞßåëðóõ÷÷úûûüüûJùø÷õôóñîëéæãáÜØ×ÔÑÏËÇÅÄÃÃÉãûÿùÚ¹°¯¯´»´¬ªª§¡œ˜¤ž©©zE-'&#"%& !!""'/+)ÿMM>Ž *g²ÙÜßæêïòóöøúúûƒýKüûúùøöõóñòîèåâÞÛØÕÔÑÏËÉÈÈÅÂÌáõÿúݾ²¯¯²³­±´­§¢ž¡¤•‘¥œj@-%'"#!"" !#! '.+)ÿMM>ŽS¡ÓÙÙäëëïóöøùûüüýýþþýüûúø÷õóõòêçâßßÜÙÖ€Ó.ÏËÉÇÅÃÆÔðÿúÝÁ·´±®¬°®«¯ª§¯­¨¬´¶Y8(# "(""#!"#€")0+)ÿMM>?‡ÉÙØÝåêëîóöøúüýþNÿþýþþýüûúøöóòñìèãâàßÝÙÕÕÓÑËÊÌÍÈÀ¼ØüÿòÕź²®¬«§¦¬«¨ª°ÒíïëÅ€J-"""# !! !")1-,ÿMM>Œ )lµÔÔÙßâçìñôöøúûýƒþÿ€þHüüúùöôðïíéçåáßÞÛØÕÑÑÎÍÏÑËÅ¿ÎôÿôØÈ½³³°¬©¥¢¦°½×úÿúÿü¼i8(## #!'.-,ÿMM>ŒM›ÌÒÓÛáäèíòöøúüûý†þIýýüûùøöóñîìéçâáÞÛÚØÕÒÑÑÐÎËËÎÑíÿöÚÉÁ¸µ³°¬¨©»ÛóýíÓÇÍèÞ–Q/##  #$(/-)ÿMM>Œ 3z¼ÏÏÕÚáèêîòõøúüýý†þýýüûúøöôòîíëéåãáÞÜÛÙ€Ô ÐÍÍÎÓÕëÿýíÖź€µ"¸Ç×ìÿüàÀ¬¢¡­Á±t>("#%# "!""'0,)ÿMM>‹V¡ÈÊÎÕÛäèêíòõ÷úüýþ€ÿ‚þ:üûúø÷ôòñîììêåãáÞÜÚÖÖÔÐÎÐÐÎÔíÿÿûãȼ¶¹ÀÕïüÿîÆ¯­¯¢œ˜™®•X/#!#%$€# (1-,ÿMM>Š 4~ºÉÍÐÓÞææèîóõøúüýý€þÿÿƒþüûúø÷õóóïìëëèåãßÜÛÙ×ÕÓÑÒ€ÓãúÿüâÆ¿¼¿ÇßýÿóǤ ¥«¨Ÿ›‘ ©u<&" €# $$ *3.-ÿMM>ŠU¡ÃÆÏÑÓÜâäèîòôøúüüýý…þIýýüûúø÷õóóðìëéåãáßàÝÜÙØÖÔÔØÙ×äúÿùÙÄÆÃ¿¿Ñöÿë颡£§¡¢”¨‘T.#"!""$# &/-,ÿMM>Š 0x·ÁÁÊÍÒÜàãèíñô÷ùûüýý„þ€ýGüûúø÷õôòñïëëíëçáÞßÞÜÚØÕÖÛâêöþÿùÙÂÅļ¸ÃéÿïǬ¦£¦©¢¢¡“ž¥s?)&#$"$"%-,+ÿMM>‰L˜¿»¾ÆËÒÜàâçìðóöøúüýþýþÿþþýüûúùø÷÷õòñîîóüûøìâÝÝßÝÚÙÚåõü€ÿ)úÝÄþº¾ßÿ÷̯©¤«³¥›§¢˜¯T1&&'#'" )1-+ÿMM>‰'l°¿¸¾ÅËÕÝÞáæêïòõ÷ùûüýþþÿýþüüûúùø÷öôñðñöûþûÿüõìãÜÚÛÚâö‚ÿ)úÜÆÃÂÁ¾¼ÎóþḨ¥«µ§©¥”¦¢i7&&'$&% !)2//ÿMM>ˆ<ˆ½½·¼ÃÉÒØÜßäéíñôöøû€üPýýþýþýüüûúúù÷øõôö÷ûþÿýùúþÿýôêâÜÝðÿþýþÿÿûäÏÈÅÂÿ½Þÿí»¨§§®¨Ÿ œ— ®G*&(%$%#!)//0ÿMM>ˆTœ¹µµ¼ÃÊÒÖÙÞáçìðòô÷ùüüûüýýü ûúúùø÷÷ôõý‚ÿ úïï÷þþûöïðûÿþý€ÿ)þòÚÍÊÈÊÀÁæÿ뻪¨¦­¬Ÿ¢›™­‘Y1)(#&"$  */,+ÿMM>ˆ&n®µ¯·¿ÂÊÓÕ×Ýâçêìðóôöùûû€üûúúùø÷÷öôöþýüÿý÷ôìêìö€ÿþþ€ÿþþ€ÿ(øãÎÇÊÌÏáûÿḮª¨±¯ž¥®Ÿ¥¤k:+&)%#" '320ÿMM>ˆ 9…¹±«ºÀ¿ÇÐÔÕÛáæèêîñôõöøùúûù€ú€ùø÷÷öõõùÿùõúõððïìéò…ÿþþ€ÿ(üöíäÛÙêûÿôÒº²ª¨°­Ÿ¦®¦“˜©{D,))$"#" ")411ÿMM>‡K—³§­¶»¿ÅÍÑÒÙßãåéìîñóõöõ÷„ø€÷ø€õøþøóôòññðïëî÷ùùöóù†ÿþüøöýÿÿîõ´­ªª«¥¤¤ ›•­ŒO/($€#$%#)1+)ÿMM>‡\¡µ¯°²·½ÆÏÎÑÖÚßâæéëîðòóõöö…÷ ø÷õõöüÿøôô€ó òñïîíëëéçëù‰ÿýöìÖ½¶µ¯¨©°«¡› £µ™]3$!€#"$!"',-,ÿMM>‡'o«±¯­®´¸ÃËËÎÓÙÝàäæéìîðñòôôõõö÷ö÷öõõýÿþ÷€õôôóòñïììééèéêïû€ÿ)þûúôíêßÕÐÆ¿º·´¯ªª­¦¡ œœª¢j9# !"$"!(*+-ÿMM>‡ 4|­§¤©±¸¹¾ÇÊËÐÖÛÞàãæéëíïðñòòóôöõ€ô€õ÷þÿþ÷€ö€õ8ôñððíìêêëèçëòúÿÿôãÜ×ÑËÊž¼º¸µ¯«±³¦£§ ™”ž§t>$!! ! !!%*,-ÿMM>‡ >ˆ­£¤ª®³¶¾ÉÉÈÎÔØÚÝáçëééìíîïñòò€óôõüÿÿýø‚÷9öôóóðïíëéçåäâãóÿÿýïÜÑÌÊÊÇÁ¼¹¸·±¬¶µ¥  ›¡œ–§F& !!#%(+..ÿMM>†-I•·±­©«²»¼ÀÆÈÌÒÖØÚßèëèçêëëíîïòñòóóôõøøýÿÿýø÷‚ø8÷ôóóðîìéæäâàãíòõýýîÚÌÇÊɽ»¸¶°®´±¥¡œ££ªƒK+!#!  #).+)ÿMM>†'R·¯¬§ª¯µ·¼ÁÅÊÐÔÖØÞææäåèééìîïððñòòõùþþ€ÿûøƒù8ø÷ôòðïíëéçäáãêåãóÿþóÛËËÑǼº¹¸±¯±«¥¢Ÿœ˜£¥®‹N($&&"!$*.,+ÿMM>†.ZŸ¬Ÿ£¥§¬·»¹½ÄÊÎÑÒ×ÚÝàáäæçèëìíîïðñòó÷üüúüÿüùúú€û9úúøõóòòððíêçââãßÞéûÿþêÎÆÉļº¼º³­ª¦¨©¢œ˜››¬–W)"&"% !(,..ÿMM>†/a¢¦˜¢¥ª±¸¸»ÂÇÉÌÑÕ×ÙÜßáãæçèêìíîïðñòóôõöøûúúûüü€û8üûù÷öøüùñìçâßÞÞßäõÿÿîÏÅž¼»¸´¯«§¦¥ œ›˜¢–[."!" &..-ÿMM>†,e¨©—œ¡¥©«°¶»¿ÂÅÈÌÑÕ×ÚÜÝßãåæçéëíîïñòóôõö÷ùùûü€ýþýýþ€ÿ0ùíçäààáàãôÿÿøÛÆÂÁ¾½Ä¿³¯¬©¦¢ žš˜‘¡—]0 "!'/+(ÿMM>†!g©¬™›©³°­¯´¸¼ÁÃÇÌÏÐÔ×ÙÛÞá€äæéìíïðñòôõöøøúûüý…þÿ0üñçäááåèìúÿÿ÷ÚÇÂÁ½»¾»³®­«¦¡¦ª¡™‘ ™_0!## #'-//ÿMM>†4 f«µ¤žª»¶ª¬³º½¿ÂÇÍÎÎÒÕ×ÚÝáããäåçêìíððòóôöøøúûüþþÿþýþþƒÿ0þ÷ëäáäïúûþÿÿñÑÆÄÁ¾¼·³²°±­§ ©²¥™“¢š^.!"! $*.22ÿMM>†- fª°¢¢ ª±ªª²¿ÃÀÀÅËÍÍÐÔÖØÙÜàâäåæèíîîðñóôõ÷øúúýÿýý…ÿþõëçêø‚ÿ$îÑÇÅÁ¾¾¼·±µ¼³§ ª¬›š¥—[/ !"" (..-ÿMM>†. c§­œœ£ª©«±¼Á¾¾ÂÆÉÉÌÒÔÕØÚÜàâãåçëíîïòòõõöøùúüþ€ÿ€þ…ÿý÷óôþÿ%þïÕÈÄÁ½ÀÆÀ³¶¹°©¢¬®œœž¬—Y/  "'.,)ÿMM>†.]¥µ¦¡  £¦«¯²·¼¾ÁÅÆÉËÎÑÔÖØÛÝàáãåçëíïðòóôöøøùýþ“ÿ&ýùäÌÅÃÁ½ÂÉÀ´²­¨¦¡©¨•›·™T+  !'*(&ÿMM>†-Z¡´«­¦¥¦¨­¯±µº½ÀÄÆÉËÍÎÑÔ×ÙÚÝßáåçêíîðòñôõ÷öûþ’ÿúòëáÍÄÅÿ½À½µ³²®¨¥£¦£›—¡¹•N&€!!&*+)ÿMM>†,Q›®¢©¨¥¨­®´¸·¹ÀÅÄÅÌÏÎÐÔÖØÙÛÞáãåéìîîïðòôôõü‡ÿþ†ÿüóå×ÎÉÈÇÆÃÀ½¿¾·²²¯©¥€¢ ˜œ¶‹I& &+*(ÿMM>†G”²›–¦¥Ÿ¦¬²»¿º¸¾€ÂÍÒÍÍÑÓÕÙÜÝßàäçêëíîðññóöû…ÿýúøú„ÿ þóßÑÎÌËÊÆÆÇÁ€»·±°²°©¡šžªœ˜°‚C$'-)&ÿMM>‡$ :‰¸¢šª¥ž£§´ÁÁ·¶»½¿ÂÈÌÊËÏÑÓØÜÜÝßãåæèì€ïðòöüþƒÿýöððôýÿþþ€ÿ+üèÔÑÑÏÌÉÇÆÆÁ¼¸·¶°²½º©ž˜š¬£›©z: #&.-,ÿMM>‡$.{±Ÿ˜¦¡ ¤²Â¼±´¹¼¿ÁÃÆÉËÎÐÑÕÚÜÜÝáäæçê€íïòöûƒÿ ýöïîíïöúùü€ÿ+øâÖÔÐÍËÍÏËÅ¿»¸µ³¯µ¿³¨°¨š¦ž£n1!$%++,ÿMM>‡+$j¥“›žœŸ£®¹´®³¸¼½ÀÂÅÊÍÏÐÐÓÖØÚÛÞâäåèêêëïðóú‚ÿ9üöðîíìíîðóöûÿÿøáÓÒÐÎÍÓ×ÏǼ¹¶±²À¹Ëä×ÀÀª¥œb, " &.*(ÿMM>‡+Y›¤šœ¢ŸŸ¤§«­¯±¸¿¾½ÁÃÇËÌÍÏÐÓÖØÙÜÞàâçèêëíîñúÿ.úõðìëêìîìëìîõþÿýëÖÐÎËÊÏÕÐÇÁÅÒÔÐÓáæëúÿþðÚ³¬R'!'3-(ÿMM>‡+G¨š§¥ £§¨¬­²Áż»¿ÂÅÇÊËÍÎÒÕ×ÚÛÜÞàãäçëëìñý€ÿþôîíêéèéììéæèóþÿþóßÐÌÊÌÓÛáÜØä÷þþÿþùñÜ´©E#! !#*1+(ÿMM>ˆ) 6¦—™§¤¡¨ª©«´ÄÁ¸»¿ÁÃÅÇÊÍÎÑÓÖרÛßßàáäèêîöÿýóëêèçæ€åæååñÿÿþôèßÜÛáíöýýû€ÿùóôëãÛ̺©’—¥t; !"!!$+-('ÿMM>ˆ)$j¢”žž› ¦¦§ª±º¸¶¸¼ÀÂÄÅÇËÍÏÐÒÔÖÙÜßÞàããêõüÿ,ýóéçåääâáàâãàçùÿþüøùúùýÿÿýüþÿýùàÌǸ«£œ œ¡œb/  !*-*'ÿMM>‰'Q˜¦—žŸ›ž¢¥¦§¬¶¹µ¶º½ÀÅÈÇÈÊÌÐÏÒÖ××ÛÝßãåìû‚ÿüðçäãâáàßÝÞÞÚÝò„ÿüñéàÛçëåÛݨ¤ž˜˜¥¡˜ª‹N% €'.,)ÿMM>‰' 8„®¡™¤§§¨«´¹µµ¹¼½ÄËÉÆÇÉÒÖÕÔÔÖØÛÞáèòúÿüóéæäâáÞÝÛÜÛÙÖ×í‚ÿ'þøåÎþ¼¿¿½º®¥§«¥››¥ž¥«w?#!" &-,+ÿMM>‰'#h¦¢• Ÿ›¡©­­ª­³´´¹¼½¿ÃÆÇÇÉÍÙÜÔÓÕÕØÛßæðûÿûîåääâÞÛÚÚÙ×ÕÒÓæüÿùàÊ¿¹¹·³¯®«¨«­¬£™˜£˜§a1 €!&2-+ÿMM>‰(H‘©›¢£™Ÿ«¯®ª©®±³¹¼»»¾ÃÆÇÈÇÎÕÓÒÒÓÖÙÜàçôþ€ÿýñàÞàáÜ€Ø2ÕÕÔÑÏ×îþÿÿþõÔÀ¾º·¶´±­§©´±¦Ÿ˜––œ«…J( ""'72.ÿMM>Š] +u®¤™¡¤¥¨ª©«®°µ»¼¼¿ÁÃÃÄÆÈËÎÏÐÒÔÖØÙÞäôþÿÿýëÙÚÚÛÚ××ÖÔÔÒÎÌËÞûÿúíåÖ¿¹º·¶²®­ª¨«§ œš™§¦j9"" €"'421ÿMM>Š-Q›©”˜››Ÿ¢¦¨ª¬¯³¸¾¿¼¾ÁÃÂÄÆÇËÎÑÒÒÓÔÕ×Úä÷ÿÿüèÔÖ5ÕÖÕÒÑÏÎÌÊÚùþëÐÊÍ¿¸º¸´®¬¯«£¡¢ ˜¢¤œªP-!'($ !! !(1//ÿMM>‹' /w©—›Ÿ¤¥¤¤©³´±µ»½»¿ÅÅÂÂÆÇÉÔÔÑÐÒÒÓÖ×ßò€ÿôÙÑÔÔÒ2ÐÎÍÎËÊØøþäÇ¿¿»¹¶´°¬´´¨¤¢¤¡š §¡k<% )-)!!$!(1/.ÿMM>‹O˜¨”—œž¥¨¤¡¨º»±²µ·º¾ÄÆÄÀŠÏÍÌÏÒÐÑÕ×ßô€ÿþèÎÏÑÑÏ€Î1ÌËËÊÈÕõÿçļº··´°®´¾µª©£Ÿœ›”–ªŠL. ##"" )310ÿMM>Œ& +p§¤—™™Ÿ §¯¸¸±°±µ·¹»ÂÈÆÄÉÈÅÊÔÓÑÓÕ×àèùÿ:øÚËÎÐÎÍÌËÉÉÇÉÏáúüÚ¹¹¸µµ´®®¹¹­§¤Ÿš™˜”¥¢i3!  (232ÿMM>ŒUD«–”›œœ ¬´®®­¬¯µ¶¶¹¾ÃÁÇßàÙéïØÏØãèõûþÿÿþüÿöÛÌÉÊÊÉÈÈÆÅÐæùÿöʳ¶¶´³°«­¯©¢ž¡¦ ˜£®„J&"€ !" #% &./.ÿMM>""a ¡”¤«¬¨£¥¤©¬¬­±´¶¹»»·ÍõÿüôäÐÍØé÷ÿ,õéäïüúáÍÆÃÃÄÅÆÍäùÿýåÁ·µµ´°«ª©§¦¢œ£¬¦›¬š^4!€ !!"$(#&/,+ÿMM>d 5|§£³·°Ÿš£°µ­©¬±µµ·µ²ÚþôâÌÁÂÊÕåûÿÿýíÕÍÊÎÜòþñÜÓÌÆÄÍãúÿþèȼ¸²±°­©§©«ª¢ž¦©¢š¦¦t=' (3.-ÿMM>ŽcJ¨Ÿ£«°© ¦¸»«¥ª¯³±±¯«ÛþÓ¼½¼½ÈÕïþÿÿñÎÂÃÅÄÄÎìÿÿúîâÞãøÿúèɹ»´®²²¬ª§¨­§œ¡© š¦®‰M) ! (10/ÿMM>Ž "^¥“• §ª©±¶¬¤¨­±¯¯¸±ÊôßÃÈÇÄÕãû€ÿ?äÀÀÂÃÄÂÁÉãöÿÿþýýÿûâÉ»¶µ°³½·©¬«¦§¢›¢¥•š¯–[1 !## !!!&00/ÿMM> -n£ “œ¤§¦¨§¥§©¬«±ÉÊÄÞ÷ÞÚÞâñù€ÿûÒ¿ÀÁÁ¾ÀÍæýÿ.ï̾¹±­¯»¼¬¨­©¤ ›™Ÿ ­Ÿg6"! !!$&.0.ÿMM>8|§ ¤œœžœ¢¥¦¦¥¨³ÊÓÌÑõ÷ô÷þÿ÷âÀ¼»½½¿ÁÁÃÀ½Îó€ÿ/ôØÃ½µ¬®³±¬¦©§žœš––˜£µªt@%!$"#'.//ÿMM>‘Bƒ«®¦˜œ£¦£¡£¥«·ÆÍÊÜöÿEõïíéÒÁ»º¹»¼ÁÈÃÅÛâÝîÿýíÓÄ¿¹¯ª¯°§©¬£œž™˜™œ®¯|H-   $%&(2/0ÿMM>‘`F‰­£ž¢¤«¨Ÿž§±·¾ÅÑíýÿþøâÎÈÇø¶¸½À·¹ÀÆ½Íøÿùøþíĵ¹·°©¨§¨¯¯¨¤ª®¤¢§¬ª†L+$!""! %(411ÿMM>’( J†¨¯©ž ¢œ¢§®±¯½âüÿìÛͺ³µ´´³µ¶º¾µ¶¹¸Åêÿ"ýÙ¯¬®«©¨¦¢¤®©Ÿª·±ž–¢¶¯‚P0 !€  &221ÿMM>“& H‡²®–‘ššžª«©­¯ÁêÿúÔµ««¯¯®°®­²³³·¹¹¿âÿ3þîÄ«ª¨¦¨¨¢¢¥§¢œ¥¬Ÿ”©­†O/&!!$#!!'1/.ÿMM>”% E¨©—•ž¥¦§®¼ÖóÿúÛ¶¨««©©¯²®®´¿ÇÈÆÚûÿ&öѲ©§¥¥ªª£ ¤£š Ÿ“™ª¥~O1'#" "##"" &€ )2/.ÿMM>•%—Z0b–­§™”—žµÕòÿÿåÀ¬©ª¬±¼Ïíúöùÿþüøðâßëöÿòʯ¤£¡ Ÿ››š—–“›§ª“f=+#! " $"!!!!!)1/.ÿMM>˜&O¤ª‘“±áüÿý̦ž¡¥¦«Çñþÿÿûÿ6ùíÚÑæÿ컩¡œœš™™›œ—“¢¯¢W9' !'%"# %# " #""'€,ÿMM>™ ;g“ª¦‘¥åÿÿ㵩©£¦¦·ÞþÿÿõÑÙð€ÿ8ýôéñÿí¼¨§š˜œžŸ ˜›§©“mK1#!""$&$!$# # $! !*.,,ÿMM>š)Mw™£«ÚÿÿÎ¥ª­ ¹àùÿÿîÌ®´Ö÷ùú€ÿ5þÿ÷Ô³¨ ¡¥ž˜¡¥¥¨™zZ@."!&&#$$&# ! $!#'# "!*2.,ÿMM>œ 2U|–¸æÿä©™šš¦áýÿÿûȪ¦«ÈØÍå‚ÿ3û⻢ž£¥¢´±šaE2'#" &-$"#!!"! $" "$ '2/,ÿMM>T6Ts™ÌÕ³›”“¬åðÛÞÓ© §®¹¶·Ùúûþþÿø×®—•¤´°¥˜€aI6-'##$'!#!!&# "#%!##  %'0-)ÿMM>Ÿ1Ih†š¦ª¦¯Õ渮²§Ÿ¤ª§¨¼ÈÜñÿ⹦¦¨ ŒrWD7,$ $%€#!%$ !$# " "$ (/+)ÿMM>¡P &:Un‚”¢ºÎ·­´°©©¢žŸ©·ËèýøèÚĪ•†wbM£N *¦",7DQZbinqx€|wrmf\SK?5.+&#€ )!!'&!$%"$$%&$"$$!"!%$ "'&" (.+)ÿMM>ª. !&)+6CA>@;70,($""#'%$# #"# !$%$€#&'&# "#$#" # &-,+ÿMM>®<'#$&# &$! ! !! "'! % !#&%$$% #!" € &.,+ÿMM>´  €3##! "  ()"!$##&$ $$&('%"  #! &.0/ÿMM>´  !%!   !#! ‚"$'&$"! #(%"(&##! ! ! &,0/ÿMM>´ # &%! ',&€ ""!#"!#%$$(("#%$!!"%"# &-..ÿMM>´=  !"!##!"%)$#""%'$ #((%$%"!"##!#& !# !&,..ÿMM>´  #$"$#$!#"$$€%$&&# #&"#((! ! !# !!!(.02ÿMM>´-  $%%$"#" " "#!$&##%%! "%%$ "'$! "€! &,,-ÿMM>´  "$%"!# !"! $)%" "#'-)#!%%"#"##!!  €&-+)ÿMM>µ/ !#!! !"!!!&(&"!%('#*+!%'##$#"€ "&" (.*)ÿMM>´   ! !#$#!! *"#!!""&'$!"%'$!)*"'($#! " ! $&& (.('ÿMMFµ/+#$%'(('())'(')**( ''&(,($&((&%%€&''(*''(&&(+*&(+*.-&',..-ÿLLNµU#>#,.00//02,+0120/.++,-,)*.+'),)((&&)€,++--+,.262/.1/1../€.-ÿK·L8"*03.+-00+*.0-**,*()€*€)!*+*')*('+,*((*-,*,-,13-)++*)()**&%ÿPLLKK³J 8").3,)+,,€+%,*(())&'(()'%&)*'&&''&(*(%%(**)*+*/0+(€'(&'&&$#ÿùÿùÿùÿùt8mk@ñøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøûíøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿö%øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøJ7 øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùcJ% øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS)øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùpS*ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúpS*ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþpS*îöøùùúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúýôqT**TppT* %JcppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppcJ% 7JSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSTSJ7 %)*******************************************************************************************************************%dxx-rebirth-0.58.1-d1x/arch/cocoa/tool_bundle.py000066400000000000000000000205221217717257200214340ustar00rootroot00000000000000# Create an application package. # http://www.scons.org/wiki/SubstInFileBuilder import re from SCons.Script import * from SCons.Builder import * def TOOL_SUBST(env): """Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT from the source to the target. The values of SUBST_DICT first have any construction variables expanded (its keys are not expanded). If a value of SUBST_DICT is a python callable function, it is called and the result is expanded as the value. If there's more than one source and more than one target, each target gets substituted from the corresponding source. """ env.Append(TOOLS = 'SUBST') def do_subst_in_file(targetfile, sourcefile, dict): """Replace all instances of the keys of dict with their values. For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, then all instances of %VERSION% in the file will be replaced with 1.2345 etc. """ try: f = open(sourcefile, 'rb') contents = f.read() f.close() except: raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile for (k,v) in dict.items(): contents = re.sub(k, v, contents) try: f = open(targetfile, 'wb') f.write(contents) f.close() except: raise SCons.Errors.UserError, "Can't write target file %s"%targetfile return 0 # success def subst_in_file(target, source, env): if not env.has_key('SUBST_DICT'): raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." d = dict(env['SUBST_DICT']) # copy it for (k,v) in d.items(): if callable(v): d[k] = env.subst(v()) elif SCons.Util.is_String(v): d[k]=env.subst(v) else: raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) for (t,s) in zip(target, source): return do_subst_in_file(str(t), str(s), d) def subst_in_file_string(target, source, env): """This is what gets printed on the console.""" # return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) # for (t,s) in zip(target, source)]) def subst_emitter(target, source, env): """Add dependency from substituted SUBST_DICT to target. Returns original target, source tuple unchanged. """ d = env['SUBST_DICT'].copy() # copy it for (k,v) in d.items(): if callable(v): d[k] = env.subst(v()) elif SCons.Util.is_String(v): d[k]=env.subst(v) env.Depends(target, SCons.Node.Python.Value(d)) return target, source subst_action=SCons.Action.Action(subst_in_file, subst_in_file_string) env['BUILDERS']['SubstInFile'] = env.Builder(action=subst_action, emitter=subst_emitter) # http://www.scons.org/wiki/MacOSX (modified to suit) from SCons.Defaults import SharedCheck, ProgScan from SCons.Script.SConscript import SConsEnvironment import sys import os import SCons.Node import SCons.Util import string def TOOL_BUNDLE(env): """defines env.LinkBundle() for linking bundles on Darwin/OSX, and env.MakeBundle() for installing a bundle into its dir. A bundle has this structure: (filenames are case SENSITIVE) sapphire.bundle/ Contents/ Info.plist (an XML key->value database; defined by BUNDLE_INFO_PLIST) PkgInfo (trivially short; defined by value of BUNDLE_PKGINFO) MacOS/ executable (the executable or shared lib, linked with Bundle()) Resources/ """ if 'BUNDLE' in env['TOOLS']: return if sys.platform == 'darwin': #if tools_verbose: print " running tool: TOOL_BUNDLE" env.Append(TOOLS = 'BUNDLE') # This is like the regular linker, but uses different vars. # XXX: NOTE: this may be out of date now, scons 0.96.91 has some bundle linker stuff built in. # Check the docs before using this. """LinkBundle = env.Builder(action=[SharedCheck, "$BUNDLECOM"], emitter="$SHLIBEMITTER", prefix = '$BUNDLEPREFIX', suffix = '$BUNDLESUFFIX', target_scanner = ProgScan, src_suffix = '$BUNDLESUFFIX', src_builder = 'SharedObject') env['BUILDERS']['LinkBundle'] = LinkBundle""" env['BUNDLEEMITTER'] = None env['BUNDLEPREFIX'] = '' env['BUNDLESUFFIX'] = '' env['BUNDLEDIRSUFFIX'] = '.bundle' #env['FRAMEWORKS'] = ['-framework Carbon', '-framework System'] env['BUNDLE'] = '$SHLINK' env['BUNDLEFLAGS'] = ' -bundle' env['BUNDLECOM'] = '$BUNDLE $BUNDLEFLAGS -o ${TARGET} $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $FRAMEWORKS' # This requires some other tools: TOOL_WRITE_VAL(env) TOOL_SUBST(env) # Common type codes are BNDL for generic bundle and APPL for application. def MakeBundle(env, bundledir, app, key, info_plist, typecode='BNDL', creator='SapP', icon_file='#macosx-install/sapphire-icon.icns', subst_dict=None, resources=[]): """Install a bundle into its dir, in the proper format""" # Substitute construction vars: for a in [bundledir, key, info_plist, icon_file, typecode, creator]: a = env.subst(a) if SCons.Util.is_List(app): app = app[0] if SCons.Util.is_String(app): app = env.subst(app) appbase = os.path.basename(app) else: appbase = os.path.basename(str(app)) if not ('.' in bundledir): bundledir += '.$BUNDLEDIRSUFFIX' bundledir = env.subst(bundledir) # substitute again suffix=bundledir[string.rfind(bundledir,'.'):] if (suffix=='.app' and typecode != 'APPL' or suffix!='.app' and typecode == 'APPL'): raise Error, "MakeBundle: inconsistent dir suffix %s and type code %s: app bundles should end with .app and type code APPL."%(suffix, typecode) if subst_dict is None: subst_dict={'%SHORTVERSION%': '$VERSION_NUM', '%LONGVERSION%': '$VERSION_NAME', '%YEAR%': '$COMPILE_YEAR', '%BUNDLE_EXECUTABLE%': appbase, '%ICONFILE%': os.path.basename(icon_file), '%CREATOR%': creator, '%TYPE%': typecode, '%BUNDLE_KEY%': key} env.Install(bundledir+'/Contents/MacOS', app) f=env.SubstInFile(bundledir+'/Contents/Info.plist', info_plist, SUBST_DICT=subst_dict) env.Depends(f,SCons.Node.Python.Value(key+creator+typecode+env['VERSION_NUM']+env['VERSION_NAME'])) env.WriteVal(target=bundledir+'/Contents/PkgInfo', source=SCons.Node.Python.Value(typecode+creator)) resources.append(icon_file) for r in resources: if SCons.Util.is_List(r): env.InstallAs(bundledir+'/Contents/Resources/'+r[1], r[0]) else: env.Install(bundledir+'/Contents/Resources', r) return [ SCons.Node.FS.default_fs.Dir(bundledir) ] # This is not a regular Builder; it's a wrapper function. # So just make it available as a method of Environment. SConsEnvironment.MakeBundle = MakeBundle def TOOL_WRITE_VAL(env): #if tools_verbose: print " running tool: TOOL_WRITE_VAL" env.Append(TOOLS = 'WRITE_VAL') def write_val(target, source, env): """Write the contents of the first source into the target. source is usually a Value() node, but could be a file.""" f = open(str(target[0]), 'wb') f.write(source[0].get_contents()) f.close() env['BUILDERS']['WriteVal'] = env.Builder(action=write_val) dxx-rebirth-0.58.1-d1x/arch/include/000077500000000000000000000000001217717257200171125ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/include/digi_audio.h000066400000000000000000000010461217717257200213610ustar00rootroot00000000000000#ifndef __DIGI_AUDIO__ #define __DIGI_AUDIO__ #include "fix.h" int digi_audio_init(); void digi_audio_reset(); void digi_audio_close(); void digi_audio_stop_all_channels(); int digi_audio_start_sound(short, fix, int, int, int, int, int ); int digi_audio_is_sound_playing(int ); int digi_audio_is_channel_playing(int ); void digi_audio_set_channel_volume(int, int ); void digi_audio_set_channel_pan(int, int ); void digi_audio_stop_sound(int ); void digi_audio_end_sound(int ); void digi_audio_set_digi_volume(int); void digi_audio_debug(); #endif dxx-rebirth-0.58.1-d1x/arch/include/digi_mixer.h000066400000000000000000000011351217717257200214030ustar00rootroot00000000000000#ifndef __DIGI_MIXER__ #define __DIGI_MIXER__ #include "fix.h" int digi_mixer_init(); void digi_mixer_close(); int digi_mixer_start_sound(short, fix, int, int, int, int, int); void digi_mixer_set_channel_volume(int, int); void digi_mixer_set_channel_pan(int, int); void digi_mixer_stop_sound(int); void digi_mixer_end_sound(int); int digi_mixer_is_sound_playing(int); int digi_mixer_is_channel_playing(int); void digi_mixer_reset(); void digi_set_max_channels(int); int digi_get_max_channels(); void digi_mixer_stop_all_channels(); void digi_mixer_set_digi_volume(int); void digi_mixer_debug(); #endif dxx-rebirth-0.58.1-d1x/arch/include/digi_mixer_music.h000066400000000000000000000006021217717257200226010ustar00rootroot00000000000000/* * Header file for music playback through SDL_mixer * * -- MD2211 (2006-04-24) */ #ifndef _SDLMIXER_MUSIC_H #define _SDLMIXER_MUSIC_H int mix_play_music(char *, int); int mix_play_file(char *, int, void (*)()); void mix_set_music_volume(int); void mix_stop_music(); void mix_pause_music(); void mix_resume_music(); void mix_pause_resume_music(); void mix_free_music(); #endif dxx-rebirth-0.58.1-d1x/arch/include/event.h000066400000000000000000000032671217717257200204140ustar00rootroot00000000000000// Event header file #ifndef _EVENT_H #define _EVENT_H #include "maths.h" typedef enum event_type { EVENT_IDLE = 0, EVENT_QUIT, EVENT_JOYSTICK_BUTTON_DOWN, EVENT_JOYSTICK_BUTTON_UP, EVENT_JOYSTICK_MOVED, EVENT_MOUSE_BUTTON_DOWN, EVENT_MOUSE_BUTTON_UP, EVENT_MOUSE_DOUBLE_CLICKED, EVENT_MOUSE_MOVED, EVENT_KEY_COMMAND, EVENT_KEY_RELEASE, EVENT_WINDOW_ACTIVATED, EVENT_WINDOW_DEACTIVATED, EVENT_WINDOW_DRAW, EVENT_WINDOW_CLOSE, EVENT_WINDOW_CLOSED, EVENT_NEWMENU_DRAW, // draw after the newmenu stuff is drawn (e.g. savegame previews) EVENT_NEWMENU_CHANGED, // an item had its value/text changed EVENT_NEWMENU_SELECTED, // user chose something - pressed enter/clicked on it EVENT_UI_DIALOG_DRAW, // draw after the dialog stuff is drawn (e.g. spinning robots) EVENT_UI_GADGET_PRESSED, // user 'pressed' a gadget EVENT_UI_LISTBOX_MOVED, EVENT_UI_LISTBOX_SELECTED, EVENT_UI_USERBOX_DRAGGED } event_type; // A vanilla event. Cast to the correct type of event according to 'type'. typedef struct d_event { event_type type; } d_event; int event_init(); // Sends input events to event handlers void event_poll(); void event_flush(); // Set and call the default event handler void set_default_handler(int (*handler)(d_event *event)); int call_default_handler(d_event *event); // Send an event to the front window as first priority, then to the windows behind if it's not modal (editor), then the default handler void event_send(d_event *event); // Sends input, idle and draw events to event handlers void event_process(); void event_toggle_focus(int activate_focus); // See how long we were idle for void event_reset_idle_seconds(); fix event_get_idle_seconds(); #endif dxx-rebirth-0.58.1-d1x/arch/include/joy.h000066400000000000000000000015671217717257200200750ustar00rootroot00000000000000/* * * Header for joystick functions * */ #ifndef _JOY_H #define _JOY_H #include "pstypes.h" #include "fix.h" #include struct d_event; #define MAX_JOYSTICKS 8 #define MAX_AXES_PER_JOYSTICK 128 #define MAX_BUTTONS_PER_JOYSTICK 128 #define MAX_HATS_PER_JOYSTICK 4 #define JOY_MAX_AXES (MAX_AXES_PER_JOYSTICK * MAX_JOYSTICKS) #define JOY_MAX_BUTTONS (MAX_BUTTONS_PER_JOYSTICK * MAX_JOYSTICKS) extern int joy_num_axes; // set to Joystick.n_axes. solve different? extern void joy_init(); extern void joy_close(); extern void event_joystick_get_axis(struct d_event *event, int *axis, int *value); extern void joy_flush(); extern int event_joystick_get_button(struct d_event *event); extern void joy_button_handler(SDL_JoyButtonEvent *jbe); extern void joy_hat_handler(SDL_JoyHatEvent *jhe); extern int joy_axis_handler(SDL_JoyAxisEvent *jae); #endif // _JOY_H dxx-rebirth-0.58.1-d1x/arch/include/jukebox.h000066400000000000000000000004311217717257200207300ustar00rootroot00000000000000#ifndef __JUKEBOX_H__ #define __JUKEBOX_H__ extern const char *const jukebox_exts[]; void jukebox_unload(); void jukebox_load(); int jukebox_play(); char *jukebox_current(); int jukebox_is_loaded(); int jukebox_is_playing(); int jukebox_numtracks(); void jukebox_list(); #endif dxx-rebirth-0.58.1-d1x/arch/include/key.h000066400000000000000000000124721217717257200200610ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for keyboard functions * */ #ifndef _KEY_H #define _KEY_H #include #include "pstypes.h" #include "fix.h" #include "event.h" #define KEY_BUFFER_SIZE 16 #define KEY_REPEAT_DELAY 400 #define KEY_REPEAT_INTERVAL 50 //========================================================================== // This installs the int9 vector and initializes the keyboard in buffered // ASCII mode. key_close simply undoes that. extern void key_init(); extern void key_close(); // Time in seconds when last key was pressed... extern fix64 keyd_time_when_last_pressed; // Stores Unicode values registered in one event_loop call extern unsigned char unicode_frame_buffer[KEY_BUFFER_SIZE]; extern void key_flush(); // Clears the 256 char buffer extern int event_key_get(d_event *event); // Get the keycode from the EVENT_KEY_COMMAND event extern int event_key_get_raw(d_event *event); // same as above but without mod states extern unsigned char key_ascii(); // Set to 1 if the key is currently down, else 0 extern volatile unsigned char keyd_pressed[]; extern volatile unsigned char keyd_last_pressed; extern volatile unsigned char keyd_last_released; extern void key_toggle_repeat(int enable); // for key_ismodlck #define KEY_ISMOD 1 #define KEY_ISLCK 2 #define KEY_SHIFTED 0x100 #define KEY_ALTED 0x200 #define KEY_CTRLED 0x400 #define KEY_DEBUGGED 0x800 #define KEY_METAED 0x1000 #define KEY_COMMAND KEY_METAED // Mac meta key #define KEY_0 0x0B #define KEY_1 0x02 #define KEY_2 0x03 #define KEY_3 0x04 #define KEY_4 0x05 #define KEY_5 0x06 #define KEY_6 0x07 #define KEY_7 0x08 #define KEY_8 0x09 #define KEY_9 0x0A #define KEY_A 0x1E #define KEY_B 0x30 #define KEY_C 0x2E #define KEY_D 0x20 #define KEY_E 0x12 #define KEY_F 0x21 #define KEY_G 0x22 #define KEY_H 0x23 #define KEY_I 0x17 #define KEY_J 0x24 #define KEY_K 0x25 #define KEY_L 0x26 #define KEY_M 0x32 #define KEY_N 0x31 #define KEY_O 0x18 #define KEY_P 0x19 #define KEY_Q 0x10 #define KEY_R 0x13 #define KEY_S 0x1F #define KEY_T 0x14 #define KEY_U 0x16 #define KEY_V 0x2F #define KEY_W 0x11 #define KEY_X 0x2D #define KEY_Y 0x15 #define KEY_Z 0x2C #define KEY_MINUS 0x0C #define KEY_EQUAL 0x0D //Note: this is what we normally think of as slash: #define KEY_DIVIDE 0x35 //Note: this is BACKslash: #define KEY_SLASH 0x2B #define KEY_COMMA 0x33 #define KEY_PERIOD 0x34 #define KEY_SEMICOL 0x27 #define KEY_LBRACKET 0x1A #define KEY_RBRACKET 0x1B #define KEY_RAPOSTRO 0x28 #define KEY_LAPOSTRO 0x29 #define KEY_ESC 0x01 #define KEY_ENTER 0x1C #define KEY_BACKSP 0x0E #define KEY_TAB 0x0F #define KEY_SPACEBAR 0x39 #define KEY_NUMLOCK 0x45 #define KEY_SCROLLOCK 0x46 #define KEY_CAPSLOCK 0x3A #define KEY_LSHIFT 0x2A #define KEY_RSHIFT 0x36 #define KEY_LALT 0x38 #define KEY_RALT 0xB8 #define KEY_LCTRL 0x1D #define KEY_RCTRL 0x9D #define KEY_LMETA 0x9E #define KEY_RMETA 0x9F #define KEY_F1 0x3B #define KEY_F2 0x3C #define KEY_F3 0x3D #define KEY_F4 0x3E #define KEY_F5 0x3F #define KEY_F6 0x40 #define KEY_F7 0x41 #define KEY_F8 0x42 #define KEY_F9 0x43 #define KEY_F10 0x44 #define KEY_F11 0x57 #define KEY_F12 0x58 #define KEY_PAD0 0x52 #define KEY_PAD1 0x4F #define KEY_PAD2 0x50 #define KEY_PAD3 0x51 #define KEY_PAD4 0x4B #define KEY_PAD5 0x4C #define KEY_PAD6 0x4D #define KEY_PAD7 0x47 #define KEY_PAD8 0x48 #define KEY_PAD9 0x49 #define KEY_PADMINUS 0x4A #define KEY_PADPLUS 0x4E #define KEY_PADPERIOD 0x53 #define KEY_PADDIVIDE 0xB5 #define KEY_PADMULTIPLY 0x37 #define KEY_PADENTER 0x9C #define KEY_INSERT 0xD2 #define KEY_HOME 0xC7 #define KEY_PAGEUP 0xC9 #define KEY_DELETE 0xD3 #define KEY_END 0xCF #define KEY_PAGEDOWN 0xD1 #define KEY_UP 0xC8 #define KEY_DOWN 0xD0 #define KEY_LEFT 0xCB #define KEY_RIGHT 0xCD #define KEY_PRINT_SCREEN 0xB7 #define KEY_PAUSE 0x61 typedef struct key_props { const char *key_text; unsigned char ascii_value; SDLKey sym; } key_props; extern const key_props key_properties[256]; #endif dxx-rebirth-0.58.1-d1x/arch/include/messagebox.h000066400000000000000000000005211217717257200214160ustar00rootroot00000000000000/* * messagebox.h * d1x-rebirth * * Display an error or warning messagebox using the OS's window server. * */ #ifndef _MESSAGEBOX_H #define _MESSAGEBOX_H // Display a warning in a messagebox extern void msgbox_warning(char *message); // Display an error in a messagebox extern void msgbox_error(const char *message); #endif dxx-rebirth-0.58.1-d1x/arch/include/mouse.h000066400000000000000000000022341217717257200204140ustar00rootroot00000000000000/* * * SDL mouse driver header * */ #ifndef MOUSE_H #define MOUSE_H #include "pstypes.h" #include "fix.h" struct d_event; struct window; #define MOUSE_MAX_BUTTONS 16 #define Z_SENSITIVITY 100 #define MBTN_LEFT 0 #define MBTN_RIGHT 1 #define MBTN_MIDDLE 2 #define MBTN_Z_UP 3 #define MBTN_Z_DOWN 4 #define MBTN_PITCH_BACKWARD 5 #define MBTN_PITCH_FORWARD 6 #define MBTN_BANK_LEFT 7 #define MBTN_BANK_RIGHT 8 #define MBTN_HEAD_LEFT 9 #define MBTN_HEAD_RIGHT 10 #define MBTN_11 11 #define MBTN_12 12 #define MBTN_13 13 #define MBTN_14 14 #define MBTN_15 15 #define MBTN_16 16 #define MOUSE_LBTN 1 #define MOUSE_RBTN 2 #define MOUSE_MBTN 4 extern void mouse_flush(); // clears all mice events... extern void mouse_init(void); extern void mouse_close(void); extern int event_mouse_get_button(struct d_event *event); extern void mouse_get_pos( int *x, int *y, int *z ); extern int mouse_in_window(struct window *wind); extern void mouse_get_delta( int *dx, int *dy, int *dz ); extern void event_mouse_get_delta(struct d_event *event, int *dx, int *dy, int *dz); extern int mouse_get_btns(); extern void mouse_toggle_cursor(int activate); #endif dxx-rebirth-0.58.1-d1x/arch/include/window.h000066400000000000000000000026251217717257200205770ustar00rootroot00000000000000/* * A 'window' is simply a canvas that can receive events. * It can be anything from a simple message box to the * game screen when playing. * * See event.c for event handling code. * * -kreator 2009-05-06 */ #ifndef DESCENT_WINDOW_H #define DESCENT_WINDOW_H #include "event.h" #include "gr.h" #include "console.h" typedef struct window window; extern window *window_create(grs_canvas *src, int x, int y, int w, int h, int (*event_callback)(window *wind, d_event *event, void *data), void *data); extern int window_close(window *wind); extern int window_exists(window *wind); extern window *window_get_front(void); extern window *window_get_first(void); extern window *window_get_next(window *wind); extern window *window_get_prev(window *wind); extern void window_select(window *wind); extern void window_set_visible(window *wind, int visible); extern int window_is_visible(window *wind); extern grs_canvas *window_get_canvas(window *wind); extern void window_update_canvases(void); extern int window_send_event(window *wind, d_event *event); extern void window_set_modal(window *wind, int modal); extern int window_is_modal(window *wind); #define WINDOW_SEND_EVENT(w, e) \ do { \ con_printf(CON_DEBUG, "Sending event %s to window of dimensions %dx%d\n", #e, window_get_canvas(w)->cv_bitmap.bm_w, window_get_canvas(w)->cv_bitmap.bm_h); \ event.type = e; \ window_send_event(w, &event); \ } while (0) #endif dxx-rebirth-0.58.1-d1x/arch/ogl/000077500000000000000000000000001217717257200162505ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/ogl/gr.c000066400000000000000000000754101217717257200170330ustar00rootroot00000000000000/* * * OGL video functions. - Added 9/15/99 Matthew Mueller * */ #define DECLARE_VARS #ifdef RPI // extra libraries for the Raspberry Pi #include "bcm_host.h" #endif #include #include #include #ifdef _MSC_VER #include #endif #if !defined(_MSC_VER) && !defined(macintosh) #include #endif #if !defined(macintosh) #include #include #include #endif #include #include #include "hudmsg.h" #include "game.h" #include "text.h" #include "gr.h" #include "gamefont.h" #include "grdef.h" #include "palette.h" #include "u_mem.h" #include "dxxerror.h" #include "inferno.h" #include "screens.h" #include "strutil.h" #include "args.h" #include "key.h" #include "physfsx.h" #include "internal.h" #include "render.h" #include "console.h" #include "config.h" #include "playsave.h" #include "vers_id.h" #include "game.h" #if defined(__APPLE__) && defined(__MACH__) #include #else #ifdef OGLES #include #include #include #include #else #include #endif #endif #ifdef OGLES int sdl_video_flags = 0; #ifdef RPI static EGL_DISPMANX_WINDOW_T nativewindow; static DISPMANX_ELEMENT_HANDLE_T dispman_element=DISPMANX_NO_HANDLE; static DISPMANX_DISPLAY_HANDLE_T dispman_display=DISPMANX_NO_HANDLE; #endif #else int sdl_video_flags = SDL_OPENGL; #endif int gr_installed = 0; int gl_initialized=0; int linedotscale=1; // scalar of glLinewidth and glPointSize - only calculated once when resolution changes int sdl_no_modeswitch=0; #ifdef OGLES EGLDisplay eglDisplay=EGL_NO_DISPLAY; EGLConfig eglConfig; EGLSurface eglSurface=EGL_NO_SURFACE; EGLContext eglContext=EGL_NO_CONTEXT; bool TestEGLError(char* pszLocation) { /* * eglGetError returns the last error that has happened using egl, * not the status of the last called function. The user has to * check after every single egl call or at least once every frame. */ EGLint iErr = eglGetError(); if (iErr != EGL_SUCCESS) { con_printf(CON_URGENT, "%s failed (%d).\n", pszLocation, iErr); return 0; } return 1; } #endif void ogl_swap_buffers_internal(void) { #ifdef OGLES eglSwapBuffers(eglDisplay, eglSurface); #else SDL_GL_SwapBuffers(); #endif } #ifdef RPI // MH: I got the following constants for vc_dispmanx_element_change_attributes() from: // http://qt.gitorious.org/qt/qtbase/commit/5933205cfcd73481cb0645fa6183103063fe3e0d // I do not know where they got them from, but OTOH, they are quite obvious. // these constants are not in any headers (yet) #define ELEMENT_CHANGE_LAYER (1<<0) #define ELEMENT_CHANGE_OPACITY (1<<1) #define ELEMENT_CHANGE_DEST_RECT (1<<2) #define ELEMENT_CHANGE_SRC_RECT (1<<3) #define ELEMENT_CHANGE_MASK_RESOURCE (1<<4) #define ELEMENT_CHANGE_TRANSFORM (1<<5) void rpi_destroy_element(void) { if (dispman_element != DISPMANX_NO_HANDLE) { DISPMANX_UPDATE_HANDLE_T dispman_update; con_printf(CON_DEBUG, "RPi: destroying display manager element\n"); dispman_update = vc_dispmanx_update_start( 0 ); if (vc_dispmanx_element_remove( dispman_update, dispman_element)) { con_printf(CON_URGENT, "RPi: failed to remove dispmanx element!\n"); } vc_dispmanx_update_submit_sync( dispman_update ); dispman_element = DISPMANX_NO_HANDLE; } } int rpi_setup_element(int x, int y, Uint32 video_flags, int update) { // this code is based on the work of Ben O'Steen // http://benosteen.wordpress.com/2012/04/27/using-opengl-es-2-0-on-the-raspberry-pi-without-x-windows/ // https://github.com/benosteen/opengles-book-samples/tree/master/Raspi DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; VC_DISPMANX_ALPHA_T alpha_descriptor; uint32_t rpi_display_device=DISPMANX_ID_MAIN_LCD; uint32_t display_width; uint32_t display_height; int success; success = graphics_get_display_size(rpi_display_device, &display_width, &display_height); if ( success < 0 ) { con_printf(CON_URGENT, "Could not get RPi display size, assuming 640x480\n"); display_width=640; display_height=480; } if ((uint32_t)x > display_width) { con_printf(CON_URGENT, "RPi: Requested width %d exceeds display width %u, scaling down!\n", x,display_width); x=(int)display_width; } if ((uint32_t)y > display_height) { con_printf(CON_URGENT, "RPi: Requested height %d exceeds display height %u, scaling down!\n", y,display_height); y=(int)display_height; } con_printf(CON_DEBUG, "RPi: display resolution %ux%u, game resolution: %dx%d (%s)\n", display_width, display_height, x, y, (video_flags & SDL_FULLSCREEN)?"fullscreen":"windowed"); if (video_flags & SDL_FULLSCREEN) { /* scale to the full display size... */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = display_width; dst_rect.height= display_height; } else { /* TODO: we could query the position of the X11 window here and try to place the ovelray exactly above that..., we would have to track window movements, though ... */ dst_rect.x = 0; dst_rect.y = 0; dst_rect.width = (uint32_t)x; dst_rect.height= (uint32_t)y; } src_rect.x = 0; src_rect.y = 0; src_rect.width = ((uint32_t)x)<< 16; src_rect.height =((uint32_t)y)<< 16; /* we do not want our overlay to be blended against the background */ alpha_descriptor.flags=DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; alpha_descriptor.opacity=0xffffffff; alpha_descriptor.mask=0; // open display, if we do not already have one ... if (dispman_display == DISPMANX_NO_HANDLE) { con_printf(CON_DEBUG, "RPi: opening display: %u\n",rpi_display_device); dispman_display = vc_dispmanx_display_open(rpi_display_device); if (dispman_display == DISPMANX_NO_HANDLE) { con_printf(CON_URGENT,"RPi: failed to open display: %u\n",rpi_display_device); } } if (dispman_element != DISPMANX_NO_HANDLE) { if (!update) { // if the element already exists, and we cannot update it, so recreate it rpi_destroy_element(); } } else { // if the element does not exist, we cannot do an update update=0; } dispman_update = vc_dispmanx_update_start( 0 ); if (update) { con_printf(CON_DEBUG, "RPi: updating display manager element\n"); vc_dispmanx_element_change_attributes ( dispman_update, nativewindow.element, ELEMENT_CHANGE_DEST_RECT | ELEMENT_CHANGE_SRC_RECT, 0 /*layer*/, 0 /*opacity*/, &dst_rect, &src_rect, 0 /*mask*/, VC_IMAGE_ROT0 /*transform*/); } else { // create a new element con_printf(CON_DEBUG, "RPi: creating display manager element\n"); dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display, 0 /*layer*/, &dst_rect, 0 /*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &alpha_descriptor, NULL /*clamp*/, VC_IMAGE_ROT0 /*transform*/); if (dispman_element == DISPMANX_NO_HANDLE) { con_printf(CON_URGENT,"RPi: failed to creat display manager elemenr\n"); } nativewindow.element = dispman_element; } nativewindow.width = display_width; nativewindow.height = display_height; vc_dispmanx_update_submit_sync( dispman_update ); return 0; } #endif // RPI #ifdef OGLES void ogles_destroy(void) { if( eglDisplay != EGL_NO_DISPLAY ) { eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT); } if (eglContext != EGL_NO_CONTEXT) { con_printf(CON_DEBUG, "EGL: destroyig context\n"); eglDestroyContext(eglDisplay, eglContext); eglContext = EGL_NO_CONTEXT; } if (eglSurface != EGL_NO_SURFACE) { con_printf(CON_DEBUG, "EGL: destroyig surface\n"); eglDestroySurface(eglDisplay, eglSurface); eglSurface = EGL_NO_SURFACE; } if (eglDisplay != EGL_NO_DISPLAY) { con_printf(CON_DEBUG, "EGL: terminating\n"); eglTerminate(eglDisplay); eglDisplay = EGL_NO_DISPLAY; } } #endif int ogl_init_window(int x, int y) { int use_x,use_y,use_bpp; Uint32 use_flags; #ifdef OGLES SDL_SysWMinfo info; Window x11Window = 0; Display* x11Display = 0; EGLint ver_maj, ver_min; EGLint configAttribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 16, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, EGL_NONE, EGL_NONE }; // explicitely request an OpenGL ES 1.x context EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE, EGL_NONE }; // explicitely request a doublebuffering window EGLint winAttribs[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE, EGL_NONE }; int iConfigs; #endif // OGLES if (gl_initialized) ogl_smash_texture_list_internal();//if we are or were fullscreen, changing vid mode will invalidate current textures SDL_WM_SetCaption(DESCENT_VERSION, "Descent"); SDL_WM_SetIcon( SDL_LoadBMP( "d1x-rebirth.bmp" ), NULL ); use_x=x; use_y=y; use_bpp=GameArg.DbgBpp; use_flags=sdl_video_flags; if (sdl_no_modeswitch) { const SDL_VideoInfo *vinfo=SDL_GetVideoInfo(); if (vinfo) { use_x=vinfo->current_w; use_y=vinfo->current_h; use_bpp=vinfo->vfmt->BitsPerPixel; use_flags=SDL_SWSURFACE | SDL_ANYFORMAT; } else { con_printf(CON_URGENT, "Could not query video info\n"); } } if (!SDL_SetVideoMode(use_x, use_y, use_bpp, use_flags)) { #ifdef RPI con_printf(CON_URGENT, "Could not set %dx%dx%d opengl video mode: %s\n (Ignored for RPI)", x, y, GameArg.DbgBpp, SDL_GetError()); #else Error("Could not set %dx%dx%d opengl video mode: %s\n", x, y, GameArg.DbgBpp, SDL_GetError()); #endif } #ifdef OGLES #ifndef RPI // NOTE: on the RPi, the EGL stuff is not connected to the X11 window, // so there is no need to destroy and recreate this ogles_destroy(); #endif SDL_VERSION(&info.version); if (SDL_GetWMInfo(&info) > 0) { if (info.subsystem == SDL_SYSWM_X11) { x11Display = info.info.x11.display; x11Window = info.info.x11.window; con_printf (CON_DEBUG, "Display: %p, Window: %i ===\n", (void*)x11Display, (int)x11Window); } } if (eglDisplay == EGL_NO_DISPLAY) { #ifdef RPI eglDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY); #else eglDisplay = eglGetDisplay((EGLNativeDisplayType)x11Display); #endif if (eglDisplay == EGL_NO_DISPLAY) { con_printf(CON_URGENT, "EGL: Error querying EGL Display\n"); } if (!eglInitialize(eglDisplay, &ver_maj, &ver_min)) { con_printf(CON_URGENT, "EGL: Error initializing EGL\n"); } else { con_printf(CON_DEBUG, "EGL: Initialized, version: major %i minor %i\n", ver_maj, ver_min); } } #ifdef RPI if (rpi_setup_element(x,y,sdl_video_flags,1)) { Error("RPi: Could not set up a %dx%d element\n", x, y); } #endif if (eglSurface == EGL_NO_SURFACE) { if (!eglChooseConfig(eglDisplay, configAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1)) { con_printf(CON_URGENT, "EGL: Error choosing config\n"); } else { con_printf(CON_DEBUG, "EGL: config chosen\n"); } #ifdef RPI eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType)&nativewindow, winAttribs); #else eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (NativeWindowType)x11Window, winAttribs); #endif if ((!TestEGLError("eglCreateWindowSurface")) || eglSurface == EGL_NO_SURFACE) { con_printf(CON_URGENT, "EGL: Error creating window surface\n"); } else { con_printf(CON_DEBUG, "EGL: Created window surface\n"); } } if (eglContext == EGL_NO_CONTEXT) { eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs); if ((!TestEGLError("eglCreateContext")) || eglContext == EGL_NO_CONTEXT) { con_printf(CON_URGENT, "EGL: Error creating context\n"); } else { con_printf(CON_DEBUG, "EGL: Created context\n"); } } eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); if (!TestEGLError("eglMakeCurrent")) { con_printf(CON_URGENT, "EGL: Error making current\n"); } else { con_printf(CON_DEBUG, "EGL: made context current\n"); } #endif linedotscale = ((x/640sc_w, grd_curscreen->sc_h); } // Set the buffer to draw to. 0 is front, 1 is back void gr_set_draw_buffer(int buf) { #ifndef OGLES glDrawBuffer((buf == 0) ? GL_FRONT : GL_BACK); #endif } const char *gl_vendor, *gl_renderer, *gl_version, *gl_extensions; void ogl_get_verinfo(void) { #ifndef OGLES gl_vendor = (const char *) glGetString (GL_VENDOR); gl_renderer = (const char *) glGetString (GL_RENDERER); gl_version = (const char *) glGetString (GL_VERSION); gl_extensions = (const char *) glGetString (GL_EXTENSIONS); con_printf(CON_VERBOSE, "OpenGL: vendor: %s\nOpenGL: renderer: %s\nOpenGL: version: %s\n",gl_vendor,gl_renderer,gl_version); #ifdef _WIN32 dglMultiTexCoord2fARB = (glMultiTexCoord2fARB_fp)wglGetProcAddress("glMultiTexCoord2fARB"); dglActiveTextureARB = (glActiveTextureARB_fp)wglGetProcAddress("glActiveTextureARB"); dglMultiTexCoord2fSGIS = (glMultiTexCoord2fSGIS_fp)wglGetProcAddress("glMultiTexCoord2fSGIS"); dglSelectTextureSGIS = (glSelectTextureSGIS_fp)wglGetProcAddress("glSelectTextureSGIS"); #endif //add driver specific hacks here. whee. if ((d_stricmp(gl_renderer,"Mesa NVIDIA RIVA 1.0\n")==0 || d_stricmp(gl_renderer,"Mesa NVIDIA RIVA 1.2\n")==0) && d_stricmp(gl_version,"1.2 Mesa 3.0")==0) { GameArg.DbgGlIntensity4Ok=0;//ignores alpha, always black background instead of transparent. GameArg.DbgGlReadPixelsOk=0;//either just returns all black, or kills the X server entirely GameArg.DbgGlGetTexLevelParamOk=0;//returns random data.. } if (d_stricmp(gl_vendor,"Matrox Graphics Inc.")==0) { //displays garbage. reported by // redomen@crcwnet.com (render="Matrox G400" version="1.1.3 5.52.015") // orulz (Matrox G200) GameArg.DbgGlIntensity4Ok=0; } #ifdef macintosh if (d_stricmp(gl_renderer,"3dfx Voodoo 3")==0) // strangely, includes Voodoo 2 GameArg.DbgGlGetTexLevelParamOk=0; // Always returns 0 #endif #ifndef NDEBUG con_printf(CON_VERBOSE,"gl_intensity4:%i gl_luminance4_alpha4:%i gl_rgba2:%i gl_readpixels:%i gl_gettexlevelparam:%i\n",GameArg.DbgGlIntensity4Ok,GameArg.DbgGlLuminance4Alpha4Ok,GameArg.DbgGlRGBA2Ok,GameArg.DbgGlReadPixelsOk,GameArg.DbgGlGetTexLevelParamOk); #endif if (!d_stricmp(gl_extensions,"GL_EXT_texture_filter_anisotropic")==0) { glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &ogl_maxanisotropy); con_printf(CON_VERBOSE,"ogl_maxanisotropy:%f\n",ogl_maxanisotropy); } else if (GameCfg.TexFilt >= 3) GameCfg.TexFilt = 2; #endif } // returns possible (fullscreen) resolutions if any. int gr_list_modes( u_int32_t gsmodes[] ) { SDL_Rect** modes; int i = 0, modesnum = 0; #ifdef OGLES int sdl_check_flags = SDL_FULLSCREEN; // always use Fullscreen as lead. #else int sdl_check_flags = SDL_OPENGL | SDL_FULLSCREEN; // always use Fullscreen as lead. #endif if (sdl_no_modeswitch) { /* TODO: we could use the tvservice to list resolutions on the RPi */ return 0; } modes = SDL_ListModes(NULL, sdl_check_flags); if (modes == (SDL_Rect**)0) // check if we get any modes - if not, return 0 return 0; if (modes == (SDL_Rect**)-1) { return 0; // can obviously use any resolution... strange! } else { for (i = 0; modes[i]; ++i) { if (modes[i]->w > 0xFFF0 || modes[i]->h > 0xFFF0 // resolutions saved in 32bits. so skip bigger ones (unrealistic in 2010) (changed to 0xFFF0 to fix warning) || modes[i]->w < 320 || modes[i]->h < 200) // also skip everything smaller than 320x200 continue; gsmodes[modesnum] = SM(modes[i]->w,modes[i]->h); modesnum++; if (modesnum >= 50) // that really seems to be enough big boy. break; } return modesnum; } } int gr_check_mode(u_int32_t mode) { unsigned int w, h; w=SM_W(mode); h=SM_H(mode); if (sdl_no_modeswitch == 0) { return SDL_VideoModeOK(w, h, GameArg.DbgBpp, sdl_video_flags); } else { // just tell the caller that any mode is valid... return 32; } } int gr_set_mode(u_int32_t mode) { unsigned int w, h; char *gr_bm_data; if (mode<=0) return 0; w=SM_W(mode); h=SM_H(mode); if (!gr_check_mode(mode)) { con_printf(CON_URGENT,"Cannot set %ix%i. Fallback to 640x480\n",w,h); w=640; h=480; Game_screen_mode=mode=SM(w,h); } gr_bm_data=(char *)grd_curscreen->sc_canvas.cv_bitmap.bm_data;//since we use realloc, we want to keep this pointer around. memset( grd_curscreen, 0, sizeof(grs_screen)); grd_curscreen->sc_mode = mode; grd_curscreen->sc_w = w; grd_curscreen->sc_h = h; grd_curscreen->sc_aspect = fixdiv(grd_curscreen->sc_w*GameCfg.AspectX,grd_curscreen->sc_h*GameCfg.AspectY); gr_init_canvas(&grd_curscreen->sc_canvas, d_realloc(gr_bm_data,w*h), BM_OGL, w, h); gr_set_current_canvas(NULL); ogl_init_window(w,h);//platform specific code ogl_get_verinfo(); OGL_VIEWPORT(0,0,w,h); ogl_init_state(); gamefont_choose_game_font(w,h); return 0; } #define GLstrcmptestr(a,b) if (d_stricmp(a,#b)==0 || d_stricmp(a,"GL_" #b)==0)return GL_ ## b; int ogl_atotexfilti(char *a,int min) { GLstrcmptestr(a,NEAREST); GLstrcmptestr(a,LINEAR); if (min) {//mipmaps are valid only for the min filter GLstrcmptestr(a,NEAREST_MIPMAP_NEAREST); GLstrcmptestr(a,NEAREST_MIPMAP_LINEAR); GLstrcmptestr(a,LINEAR_MIPMAP_NEAREST); GLstrcmptestr(a,LINEAR_MIPMAP_LINEAR); } Error("unknown/invalid texture filter %s\n",a); } #ifdef _WIN32 char *OglLibPath="opengl32.dll"; int ogl_rt_loaded=0; int ogl_init_load_library(void) { int retcode=0; if (!ogl_rt_loaded) { retcode = OpenGL_LoadLibrary(true); if(retcode) { if(!glEnd) { Error("Opengl: Functions not imported\n"); } } else { Error("Opengl: error loading %s\n", OglLibPath); } ogl_rt_loaded=1; } return retcode; } #endif void gr_set_attributes(void) { #ifndef OGLES SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,0); SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,0); SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE,0); SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,0); SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE,0); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL,GameCfg.VSync); if (GameCfg.Multisample) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); } else { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } #endif ogl_smash_texture_list_internal(); } int gr_init(int mode) { #ifdef RPI char sdl_driver[32]; char *sdl_driver_ret; #endif int retcode; // Only do this function once! if (gr_installed==1) return -1; #ifdef RPI // Initialize the broadcom host library // we have to call this before we can create an OpenGL ES context bcm_host_init(); // Check if we are running with SDL directfb driver ... sdl_driver_ret=SDL_VideoDriverName(sdl_driver,32); if (sdl_driver_ret) { if (strcmp(sdl_driver_ret,"x11")) { con_printf(CON_URGENT,"RPi: activating hack for console driver\n"); sdl_no_modeswitch=1; } } #endif #ifdef _WIN32 ogl_init_load_library(); #endif if (!GameCfg.WindowMode && !GameArg.SysWindow) sdl_video_flags|=SDL_FULLSCREEN; if (GameArg.SysNoBorders) sdl_video_flags|=SDL_NOFRAME; gr_set_attributes(); ogl_init_texture_list_internal(); MALLOC( grd_curscreen,grs_screen,1 ); memset( grd_curscreen, 0, sizeof(grs_screen)); grd_curscreen->sc_canvas.cv_bitmap.bm_data = NULL; // Set the mode. if ((retcode=gr_set_mode(mode))) return retcode; grd_curscreen->sc_canvas.cv_color = 0; grd_curscreen->sc_canvas.cv_fade_level = GR_FADE_OFF; grd_curscreen->sc_canvas.cv_blend_func = GR_BLEND_NORMAL; grd_curscreen->sc_canvas.cv_drawmode = 0; grd_curscreen->sc_canvas.cv_font = NULL; grd_curscreen->sc_canvas.cv_font_fg_color = 0; grd_curscreen->sc_canvas.cv_font_bg_color = 0; gr_set_current_canvas( &grd_curscreen->sc_canvas ); ogl_init_pixel_buffers(256, 128); // for gamefont_init gr_installed = 1; return 0; } void gr_close() { ogl_brightness_r = ogl_brightness_g = ogl_brightness_b = 0; if (gl_initialized) { ogl_smash_texture_list_internal(); } if (grd_curscreen) { if (grd_curscreen->sc_canvas.cv_bitmap.bm_data) d_free(grd_curscreen->sc_canvas.cv_bitmap.bm_data); d_free(grd_curscreen); } ogl_close_pixel_buffers(); #ifdef _WIN32 if (ogl_rt_loaded) OpenGL_LoadLibrary(false); #endif #ifdef OGLES ogles_destroy(); #ifdef RPI con_printf(CON_DEBUG, "RPi: cleanuing up\n"); if (dispman_display != DISPMANX_NO_HANDLE) { rpi_destroy_element(); con_printf(CON_DEBUG, "RPi: closing display\n"); vc_dispmanx_display_close(dispman_display); dispman_display = DISPMANX_NO_HANDLE; } #endif #endif } extern int r_upixelc; void ogl_upixelc(int x, int y, int c) { GLfloat vertex_array[] = { (x+grd_curcanv->cv_bitmap.bm_x)/(float)last_width, 1.0-(y+grd_curcanv->cv_bitmap.bm_y)/(float)last_height }; GLfloat color_array[] = { CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), 1.0, CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), 1.0, CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), 1.0, CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), 1.0 }; r_upixelc++; OGL_DISABLE(TEXTURE_2D); glPointSize(linedotscale); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_POINTS, 0, 1); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } unsigned char ogl_ugpixel( grs_bitmap * bitmap, int x, int y ) { GLint gl_draw_buffer; ubyte buf[4]; #ifndef OGLES glGetIntegerv(GL_DRAW_BUFFER, &gl_draw_buffer); glReadBuffer(gl_draw_buffer); #endif glReadPixels(bitmap->bm_x + x, SHEIGHT - bitmap->bm_y - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buf); return gr_find_closest_color(buf[0]/4, buf[1]/4, buf[2]/4); } void ogl_urect(int left,int top,int right,int bot) { GLfloat xo, yo, xf, yf, color_r, color_g, color_b, color_a; GLfloat color_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; GLfloat vertex_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; int c=COLOR; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); xo=(left+grd_curcanv->cv_bitmap.bm_x)/(float)last_width; xf = (right + 1 + grd_curcanv->cv_bitmap.bm_x) / (float)last_width; yo=1.0-(top+grd_curcanv->cv_bitmap.bm_y)/(float)last_height; yf = 1.0 - (bot + 1 + grd_curcanv->cv_bitmap.bm_y) / (float)last_height; OGL_DISABLE(TEXTURE_2D); color_r = CPAL2Tr(c); color_g = CPAL2Tg(c); color_b = CPAL2Tb(c); if (grd_curcanv->cv_fade_level >= GR_FADE_OFF) color_a = 1.0; else color_a = 1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0); color_array[0] = color_array[4] = color_array[8] = color_array[12] = color_r; color_array[1] = color_array[5] = color_array[9] = color_array[13] = color_g; color_array[2] = color_array[6] = color_array[10] = color_array[14] = color_b; color_array[3] = color_array[7] = color_array[11] = color_array[15] = color_a; vertex_array[0] = xo; vertex_array[1] = yo; vertex_array[2] = xo; vertex_array[3] = yf; vertex_array[4] = xf; vertex_array[5] = yf; vertex_array[6] = xf; vertex_array[7] = yo; glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS glDisableClientState(GL_VERTEX_ARRAY); } void ogl_ulinec(int left,int top,int right,int bot,int c) { GLfloat xo,yo,xf,yf; GLfloat color_array[] = { CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0), CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0), CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), 1.0, CPAL2Tr(c), CPAL2Tg(c), CPAL2Tb(c), (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0) }; GLfloat vertex_array[] = { 0.0, 0.0, 0.0, 0.0 }; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); xo = (left + grd_curcanv->cv_bitmap.bm_x + 0.5) / (float)last_width; xf = (right + grd_curcanv->cv_bitmap.bm_x + 1.0) / (float)last_width; yo = 1.0 - (top + grd_curcanv->cv_bitmap.bm_y + 0.5) / (float)last_height; yf = 1.0 - (bot + grd_curcanv->cv_bitmap.bm_y + 1.0) / (float)last_height; OGL_DISABLE(TEXTURE_2D); vertex_array[0] = xo; vertex_array[1] = yo; vertex_array[2] = xf; vertex_array[3] = yf; glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_LINES, 0, 2); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } GLfloat last_r=0, last_g=0, last_b=0; int do_pal_step=0; void ogl_do_palfx(void) { GLfloat color_array[] = { last_r, last_g, last_b, 1.0, last_r, last_g, last_b, 1.0, last_r, last_g, last_b, 1.0, last_r, last_g, last_b, 1.0 }; GLfloat vertex_array[] = { 0,0,0,1,1,1,1,0 }; OGL_DISABLE(TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); if (do_pal_step) { glEnable(GL_BLEND); glBlendFunc(GL_ONE,GL_ONE); } else return; glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } int ogl_brightness_ok = 0; int ogl_brightness_r = 0, ogl_brightness_g = 0, ogl_brightness_b = 0; static int old_b_r = 0, old_b_g = 0, old_b_b = 0; void gr_palette_step_up(int r, int g, int b) { old_b_r = ogl_brightness_r; old_b_g = ogl_brightness_g; old_b_b = ogl_brightness_b; ogl_brightness_r = max(r + gr_palette_gamma, 0); ogl_brightness_g = max(g + gr_palette_gamma, 0); ogl_brightness_b = max(b + gr_palette_gamma, 0); if (!ogl_brightness_ok) { last_r = ogl_brightness_r / 63.0; last_g = ogl_brightness_g / 63.0; last_b = ogl_brightness_b / 63.0; do_pal_step = (r || g || b || gr_palette_gamma); } else { do_pal_step = 0; } } #undef min static inline int min(int x, int y) { return x < y ? x : y; } void gr_palette_load( ubyte *pal ) { int i; for (i=0; i<768; i++ ) { gr_current_pal[i] = pal[i]; if (gr_current_pal[i] > 63) gr_current_pal[i] = 63; } gr_palette_step_up(0, 0, 0); // make ogl_setbrightness_internal get run so that menus get brightened too. init_computed_colors(); } void gr_palette_read(ubyte * pal) { int i; for (i=0; i<768; i++ ) { pal[i]=gr_current_pal[i]; if (pal[i] > 63) pal[i] = 63; } } #define GL_BGR_EXT 0x80E0 typedef struct { unsigned char TGAheader[12]; unsigned char header[6]; } TGA_header; //writes out an uncompressed RGB .tga file //if we got really spiffy, we could optionally link in libpng or something, and use that. void write_bmp(char *savename,int w,int h,unsigned char *buf) { PHYSFS_file* TGAFile; TGA_header TGA; GLbyte HeightH,HeightL,WidthH,WidthL; unsigned int pixel; unsigned char *rgbaBuf; buf = (unsigned char*)d_calloc(w*h*4,sizeof(unsigned char)); rgbaBuf = (unsigned char*) d_calloc(w * h * 4, sizeof(unsigned char)); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaBuf); for(pixel = 0; pixel < w * h; pixel++) { *(buf + pixel * 3) = *(rgbaBuf + pixel * 4 + 2); *(buf + pixel * 3 + 1) = *(rgbaBuf + pixel * 4 + 1); *(buf + pixel * 3 + 2) = *(rgbaBuf + pixel * 4); } d_free(rgbaBuf); if (!(TGAFile = PHYSFSX_openWriteBuffered(savename))) { con_printf(CON_URGENT,"Could not create TGA file to dump screenshot!"); d_free(buf); return; } HeightH = (GLbyte)(h / 256); HeightL = (GLbyte)(h % 256); WidthH = (GLbyte)(w / 256); WidthL = (GLbyte)(w % 256); // Write TGA Header TGA.TGAheader[0] = 0; TGA.TGAheader[1] = 0; TGA.TGAheader[2] = 2; TGA.TGAheader[3] = 0; TGA.TGAheader[4] = 0; TGA.TGAheader[5] = 0; TGA.TGAheader[6] = 0; TGA.TGAheader[7] = 0; TGA.TGAheader[8] = 0; TGA.TGAheader[9] = 0; TGA.TGAheader[10] = 0; TGA.TGAheader[11] = 0; TGA.header[0] = (GLbyte) WidthL; TGA.header[1] = (GLbyte) WidthH; TGA.header[2] = (GLbyte) HeightL; TGA.header[3] = (GLbyte) HeightH; TGA.header[4] = (GLbyte) 24; TGA.header[5] = 0; PHYSFS_write(TGAFile,&TGA,sizeof(TGA_header),1); PHYSFS_write(TGAFile,buf,w*h*3*sizeof(unsigned char),1); PHYSFS_close(TGAFile); d_free(buf); } void save_screen_shot(int automap_flag) { static int savenum=0; char savename[13+sizeof(SCRNS_DIR)]; unsigned char *buf; if (!GameArg.DbgGlReadPixelsOk){ if (!automap_flag) HUD_init_message_literal(HM_DEFAULT, "glReadPixels not supported on your configuration"); return; } stop_time(); if (!PHYSFSX_exists(SCRNS_DIR,0)) PHYSFS_mkdir(SCRNS_DIR); //try making directory do { sprintf(savename, "%sscrn%04d.tga",SCRNS_DIR, savenum++); } while (PHYSFSX_exists(savename,0)); if (!automap_flag) HUD_init_message(HM_DEFAULT, "%s 'scrn%04d.tga'", TXT_DUMPING_SCREEN, savenum-1 ); #ifndef OGLES glReadBuffer(GL_FRONT); #endif buf = d_malloc(grd_curscreen->sc_w*grd_curscreen->sc_h*3); write_bmp(savename,grd_curscreen->sc_w,grd_curscreen->sc_h,buf); d_free(buf); start_time(); } dxx-rebirth-0.58.1-d1x/arch/ogl/ogl.c000066400000000000000000001467411217717257200172120ustar00rootroot00000000000000/* * * Graphics support functions for OpenGL. * */ //#include #ifdef _WIN32 #include #include #endif #if defined(__APPLE__) && defined(__MACH__) #include #include #else #ifdef OGLES #include #else #include #include #endif #endif #include #include #include #include "3d.h" #include "piggy.h" #include "../../3d/globvars.h" #include "dxxerror.h" #include "texmap.h" #include "palette.h" #include "rle.h" #include "console.h" #include "u_mem.h" #ifdef HAVE_LIBPNG #include "pngfile.h" #endif #include "segment.h" #include "textures.h" #include "texmerge.h" #include "effects.h" #include "weapon.h" #include "powerup.h" #include "laser.h" #include "player.h" #include "polyobj.h" #include "gamefont.h" #include "byteswap.h" #include "internal.h" #include "gauges.h" #include "playsave.h" #include "args.h" //change to 1 for lots of spew. #if 0 #define glmprintf(0,a) con_printf(CON_DEBUG, a) #else #define glmprintf(a) #endif #ifndef M_PI #define M_PI 3.14159 #endif #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) || defined(__sun__) || defined(macintosh) #define cosf(a) cos(a) #define sinf(a) sin(a) #endif unsigned char *ogl_pal=gr_palette; int last_width=-1,last_height=-1; int GL_TEXTURE_2D_enabled=-1; int GL_texclamp_enabled=-1; GLfloat ogl_maxanisotropy = 0; int r_texcount = 0, r_cachedtexcount = 0; #ifdef OGLES int ogl_rgba_internalformat = GL_RGBA; int ogl_rgb_internalformat = GL_RGB; #else int ogl_rgba_internalformat = GL_RGBA8; int ogl_rgb_internalformat = GL_RGB8; #endif GLfloat *sphere_va = NULL, *circle_va = NULL, *disk_va = NULL; GLfloat *secondary_lva[3]={NULL, NULL, NULL}; int r_polyc,r_tpolyc,r_bitmapc,r_ubitbltc,r_upixelc; extern int linedotscale; #define f2glf(x) (f2fl(x)) #define OGL_BINDTEXTURE(a) glBindTexture(GL_TEXTURE_2D, a); ogl_texture ogl_texture_list[OGL_TEXTURE_LIST_SIZE]; int ogl_texture_list_cur; /* some function prototypes */ #define GL_TEXTURE0_ARB 0x84C0 extern GLubyte *pixels; extern GLubyte *texbuf; void ogl_filltexbuf(unsigned char *data, GLubyte *texp, int truewidth, int width, int height, int dxo, int dyo, int twidth, int theight, int type, int bm_flags, int data_format); void ogl_loadbmtexture(grs_bitmap *bm); int ogl_loadtexture(unsigned char *data, int dxo, int dyo, ogl_texture *tex, int bm_flags, int data_format, int texfilt); void ogl_freetexture(ogl_texture *gltexture); #ifdef OGLES // Replacement for gluPerspective void perspective(double fovy, double aspect, double zNear, double zFar) { double xmin, xmax, ymin, ymax; glMatrixMode(GL_PROJECTION); glLoadIdentity(); ymax = zNear * tan(fovy * M_PI / 360.0); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar); glMatrixMode(GL_MODELVIEW); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glDepthMask(GL_TRUE); } #endif void ogl_init_texture_stats(ogl_texture* t){ t->prio=0.3;//default prio t->numrend=0; } void ogl_init_texture(ogl_texture* t, int w, int h, int flags) { t->handle = 0; #ifndef OGLES if (flags & OGL_FLAG_NOCOLOR) { // use GL_INTENSITY instead of GL_RGB if (flags & OGL_FLAG_ALPHA) { if (GameArg.DbgGlIntensity4Ok) { t->internalformat = GL_INTENSITY4; t->format = GL_LUMINANCE; } else if (GameArg.DbgGlLuminance4Alpha4Ok) { t->internalformat = GL_LUMINANCE4_ALPHA4; t->format = GL_LUMINANCE_ALPHA; } else if (GameArg.DbgGlRGBA2Ok) { t->internalformat = GL_RGBA2; t->format = GL_RGBA; } else { t->internalformat = ogl_rgba_internalformat; t->format = GL_RGBA; } } else { // there are certainly smaller formats we could use here, but nothing needs it ATM. t->internalformat = ogl_rgb_internalformat; t->format = GL_RGB; } } else { #endif if (flags & OGL_FLAG_ALPHA) { t->internalformat = ogl_rgba_internalformat; t->format = GL_RGBA; } else { t->internalformat = ogl_rgb_internalformat; t->format = GL_RGB; } #ifndef OGLES } #endif t->wrapstate = -1; t->lw = t->w = w; t->h = h; ogl_init_texture_stats(t); } void ogl_reset_texture(ogl_texture* t) { ogl_init_texture(t, 0, 0, 0); } void ogl_reset_texture_stats_internal(void){ int i; for (i=0;i0){ ogl_init_texture_stats(&ogl_texture_list[i]); } } void ogl_init_texture_list_internal(void){ int i; ogl_texture_list_cur=0; for (i=0;i0){ glDeleteTextures( 1, &ogl_texture_list[i].handle ); ogl_texture_list[i].handle=0; } ogl_texture_list[i].wrapstate = -1; } } ogl_texture* ogl_get_free_texture(void){ int i; for (i=0;i=OGL_TEXTURE_LIST_SIZE) ogl_texture_list_cur=0; } Error("OGL: texture list full!\n"); } void ogl_texture_stats(void) { int used = 0, usedother = 0, usedidx = 0, usedrgb = 0, usedrgba = 0; int databytes = 0, truebytes = 0, datatexel = 0, truetexel = 0, i; int prio0=0,prio1=0,prio2=0,prio3=0,prioh=0; GLint idx, r, g, b, a, dbl, depth; int res, colorsize, depthsize; ogl_texture* t; for (i=0;ihandle>0){ used++; datatexel+=t->w*t->h; truetexel+=t->tw*t->th; databytes+=t->bytesu; truebytes+=t->bytes; if (t->prio<0.299)prio0++; else if (t->prio<0.399)prio1++; else if (t->prio<0.499)prio2++; else if (t->prio<0.599)prio3++; else prioh++; if (t->format == GL_RGBA) usedrgba++; else if (t->format == GL_RGB) usedrgb++; #ifndef OGLES else if (t->format == GL_COLOR_INDEX) usedidx++; #endif else usedother++; } } res = SWIDTH * SHEIGHT; #ifndef OGLES glGetIntegerv(GL_INDEX_BITS, &idx); #endif glGetIntegerv(GL_RED_BITS, &r); glGetIntegerv(GL_GREEN_BITS, &g); glGetIntegerv(GL_BLUE_BITS, &b); glGetIntegerv(GL_ALPHA_BITS, &a); #ifndef OGLES glGetIntegerv(GL_DOUBLEBUFFER, &dbl); #endif dbl += 1; glGetIntegerv(GL_DEPTH_BITS, &depth); gr_set_current_canvas(NULL); gr_set_curfont( GAME_FONT ); gr_set_fontcolor( BM_XRGB(255,255,255),-1 ); colorsize = (idx * res * dbl) / 8; depthsize = res * depth / 8; gr_printf(FSPACX(2),FSPACY(1),"%i flat %i tex %i bitmaps",r_polyc,r_tpolyc,r_bitmapc); gr_printf(FSPACX(2), FSPACY(1)+LINE_SPACING, "%i(%i,%i,%i,%i) %iK(%iK wasted) (%i postcachedtex)", used, usedrgba, usedrgb, usedidx, usedother, truebytes / 1024, (truebytes - databytes) / 1024, r_texcount - r_cachedtexcount); gr_printf(FSPACX(2), FSPACY(1)+(LINE_SPACING*2), "%ibpp(r%i,g%i,b%i,a%i)x%i=%iK depth%i=%iK", idx, r, g, b, a, dbl, colorsize / 1024, depth, depthsize / 1024); gr_printf(FSPACX(2), FSPACY(1)+(LINE_SPACING*3), "total=%iK", (colorsize + depthsize + truebytes) / 1024); } void ogl_bindbmtex(grs_bitmap *bm){ if (bm->gltexture==NULL || bm->gltexture->handle<=0) ogl_loadbmtexture(bm); OGL_BINDTEXTURE(bm->gltexture->handle); bm->gltexture->numrend++; } //gltexture MUST be bound first void ogl_texwrap(ogl_texture *gltexture,int state) { if (gltexture->wrapstate != state || gltexture->numrend < 1) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, state); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, state); gltexture->wrapstate = state; } } //crude texture precaching //handles: powerups, walls, weapons, polymodels, etc. //it is done with the horrid do_special_effects kludge so that sides that have to be texmerged and have animated textures will be correctly cached. //similarly, with the objects(esp weapons), we could just go through and cache em all instead, but that would get ones that might not even be on the level //TODO: doors void ogl_cache_polymodel_textures(int model_num) { polymodel *po; int i; if (model_num < 0) return; po = &Polygon_models[model_num]; for (i=0;in_textures;i++) { ogl_loadbmtexture(&GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index]); } } void ogl_cache_vclip_textures(vclip *vc){ int i; for (i=0;inum_frames;i++){ PIGGY_PAGE_IN(vc->frames[i]); ogl_loadbmtexture(&GameBitmaps[vc->frames[i].index]); } } void ogl_cache_vclipn_textures(int i) { if (i >= 0 && i < VCLIP_MAXNUM) ogl_cache_vclip_textures(&Vclip[i]); } void ogl_cache_weapon_textures(int weapon_type) { weapon_info *w; if (weapon_type < 0) return; w = &Weapon_info[weapon_type]; ogl_cache_vclipn_textures(w->flash_vclip); ogl_cache_vclipn_textures(w->robot_hit_vclip); ogl_cache_vclipn_textures(w->wall_hit_vclip); if (w->render_type==WEAPON_RENDER_VCLIP) ogl_cache_vclipn_textures(w->weapon_vclip); else if (w->render_type == WEAPON_RENDER_POLYMODEL) { ogl_cache_polymodel_textures(w->model_num); ogl_cache_polymodel_textures(w->model_num_inner); } } void ogl_cache_level_textures(void) { int seg,side,i; eclip *ec; short tmap1,tmap2; grs_bitmap *bm,*bm2; struct side *sidep; int max_efx=0,ef; ogl_reset_texture_stats_internal();//loading a new lev should reset textures for (i=0,ec=Effects;ivc.num_frames>max_efx) max_efx=ec->vc.num_frames; } glmprintf((0,"max_efx:%i\n",max_efx)); for (ef=0;eftime_left=-1; } do_special_effects(); for (seg=0;segtmap_num; tmap2=sidep->tmap_num2; if (tmap1<0 || tmap1>=NumTextures){ glmprintf((0,"ogl_cache_level_textures %i %i %i %i\n",seg,side,tmap1,NumTextures)); // tmap1=0; continue; } PIGGY_PAGE_IN(Textures[tmap1]); bm = &GameBitmaps[Textures[tmap1].index]; if (tmap2 != 0){ PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]); bm2 = &GameBitmaps[Textures[tmap2&0x3FFF].index]; if (GameArg.DbgAltTexMerge == 0 || (bm2->bm_flags & BM_FLAG_SUPER_TRANSPARENT)) bm = texmerge_get_cached_bitmap( tmap1, tmap2 ); else { ogl_loadbmtexture(bm2); } } ogl_loadbmtexture(bm); } } glmprintf((0,"finished ef:%i\n",ef)); } reset_special_effects(); init_special_effects(); { // always have lasers, concs, flares. Always shows player appearance, and at least concs are always available to disappear. ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[LASER_INDEX]); ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[CONCUSSION_INDEX]); ogl_cache_weapon_textures(FLARE_ID); ogl_cache_vclipn_textures(VCLIP_PLAYER_APPEARANCE); ogl_cache_vclipn_textures(VCLIP_POWERUP_DISAPPEARANCE); ogl_cache_polymodel_textures(Player_ship->model_num); ogl_cache_vclipn_textures(Player_ship->expl_vclip_num); for (i=0;i<=Highest_object_index;i++){ if(Objects[i].render_type==RT_POWERUP){ ogl_cache_vclipn_textures(Objects[i].rtype.vclip_info.vclip_num); switch (Objects[i].id){ case POW_VULCAN_WEAPON: ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[VULCAN_INDEX]); break; case POW_SPREADFIRE_WEAPON: ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[SPREADFIRE_INDEX]); break; case POW_PLASMA_WEAPON: ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[PLASMA_INDEX]); break; case POW_FUSION_WEAPON: ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[FUSION_INDEX]); break; case POW_PROXIMITY_WEAPON: ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[PROXIMITY_INDEX]); break; case POW_HOMING_AMMO_1: case POW_HOMING_AMMO_4: ogl_cache_weapon_textures(Primary_weapon_to_weapon_info[HOMING_INDEX]); break; case POW_SMARTBOMB_WEAPON: ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[SMART_INDEX]); break; case POW_MEGA_WEAPON: ogl_cache_weapon_textures(Secondary_weapon_to_weapon_info[MEGA_INDEX]); break; } } else if(Objects[i].render_type==RT_POLYOBJ){ if (Objects[i].type == OBJ_ROBOT) { ogl_cache_vclipn_textures(Robot_info[Objects[i].id].exp1_vclip_num); ogl_cache_vclipn_textures(Robot_info[Objects[i].id].exp2_vclip_num); ogl_cache_weapon_textures(Robot_info[Objects[i].id].weapon_type); } if (Objects[i].rtype.pobj_info.tmap_override != -1) ogl_loadbmtexture(&GameBitmaps[Textures[Objects[i].rtype.pobj_info.tmap_override].index]); else ogl_cache_polymodel_textures(Objects[i].rtype.pobj_info.model_num); } } } glmprintf((0,"finished caching\n")); r_cachedtexcount = r_texcount; } bool g3_draw_line(g3s_point *p0,g3s_point *p1) { int c; GLfloat color_r, color_g, color_b; GLfloat color_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; GLfloat vertex_array[] = { f2glf(p0->p3_vec.x),f2glf(p0->p3_vec.y),-f2glf(p0->p3_vec.z), f2glf(p1->p3_vec.x),f2glf(p1->p3_vec.y),-f2glf(p1->p3_vec.z) }; c=grd_curcanv->cv_color; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); OGL_DISABLE(TEXTURE_2D); color_r = PAL2Tr(c); color_g = PAL2Tg(c); color_b = PAL2Tb(c); color_array[0] = color_array[4] = color_r; color_array[1] = color_array[5] = color_g; color_array[2] = color_array[6] = color_b; color_array[3] = color_array[7] = 1.0; glVertexPointer(3, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_LINES, 0, 2); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); return 1; } void ogl_drawcircle(int nsides, int type, GLfloat *vertex_array) { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertex_array); glDrawArrays(type, 0, nsides); glDisableClientState(GL_VERTEX_ARRAY); } GLfloat *circle_array_init(int nsides) { int i; float ang; GLfloat *vertex_array = (GLfloat *) d_malloc(sizeof(GLfloat) * nsides * 2); for(i = 0; i < nsides; i++) { ang = 2.0 * M_PI * i / nsides; vertex_array[i * 2] = cosf(ang); vertex_array[i * 2 + 1] = sinf(ang); } return vertex_array; } GLfloat *circle_array_init_2(int nsides, float xsc, float xo, float ysc, float yo) { int i; float ang; GLfloat *vertex_array = (GLfloat *) d_malloc(sizeof(GLfloat) * nsides * 2); for(i = 0; i < nsides; i++) { ang = 2.0 * M_PI * i / nsides; vertex_array[i * 2] = cosf(ang) * xsc + xo; vertex_array[i * 2 + 1] = sinf(ang) * ysc + yo; } return vertex_array; } void ogl_draw_vertex_reticle(int cross,int primary,int secondary,int color,int alpha,int size_offs) { int size=270+(size_offs*20), i; float scale = ((float)SWIDTH/SHEIGHT), ret_rgba[4], ret_dark_rgba[4]; GLfloat cross_lva[8 * 2] = { -4.0, 2.0, -2.0, 0, -3.0, -4.0, -2.0, -3.0, 4.0, 2.0, 2.0, 0, 3.0, -4.0, 2.0, -3.0, }; GLfloat primary_lva[4][4 * 2] = { { -5.5, -5.0, -6.5, -7.5, -10.0, -7.0, -10.0, -8.7 }, { -10.0, -7.0, -10.0, -8.7, -15.0, -8.5, -15.0, -9.5 }, { 5.5, -5.0, 6.5, -7.5, 10.0, -7.0, 10.0, -8.7 }, { 10.0, -7.0, 10.0, -8.7, 15.0, -8.5, 15.0, -9.5 } }; GLfloat dark_lca[16 * 4] = { 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6 }; GLfloat bright_lca[16 * 4] = { 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0 }; GLfloat cross_lca[8 * 4] = { 0.125, 0.54, 0.125, 0.6, 0.125, 1.0, 0.125, 1.0, 0.125, 0.54, 0.125, 0.6, 0.125, 1.0, 0.125, 1.0, 0.125, 0.54, 0.125, 0.6, 0.125, 1.0, 0.125, 1.0, 0.125, 0.54, 0.125, 0.6, 0.125, 1.0, 0.125, 1.0 }; GLfloat primary_lca[2][4 * 4] = { {0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6}, {0.125, 0.54, 0.125, 0.6, 0.125, 0.54, 0.125, 0.6, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0, 0.125, 1.0} }; ret_rgba[0] = PAL2Tr(color); ret_dark_rgba[0] = ret_rgba[0]/2; ret_rgba[1] = PAL2Tg(color); ret_dark_rgba[1] = ret_rgba[1]/2; ret_rgba[2] = PAL2Tb(color); ret_dark_rgba[2] = ret_rgba[2]/2; ret_rgba[3] = 1.0 - ((float)alpha / ((float)GR_FADE_LEVELS)); ret_dark_rgba[3] = ret_rgba[3]/2; for (i = 0; i < 16*4; i += 4) { bright_lca[i] = ret_rgba[0]; dark_lca[i] = ret_dark_rgba[0]; bright_lca[i+1] = ret_rgba[1]; dark_lca[i+1] = ret_dark_rgba[1]; bright_lca[i+2] = ret_rgba[2]; dark_lca[i+2] = ret_dark_rgba[2]; bright_lca[i+3] = ret_rgba[3]; dark_lca[i+3] = ret_dark_rgba[3]; } for (i = 0; i < 8*4; i += 8) { cross_lca[i] = ret_dark_rgba[0]; cross_lca[i+1] = ret_dark_rgba[1]; cross_lca[i+2] = ret_dark_rgba[2]; cross_lca[i+3] = ret_dark_rgba[3]; cross_lca[i+4] = ret_rgba[0]; cross_lca[i+5] = ret_rgba[1]; cross_lca[i+6] = ret_rgba[2]; cross_lca[i+7] = ret_rgba[3]; } primary_lca[0][0] = primary_lca[0][4] = primary_lca[1][8] = primary_lca[1][12] = ret_rgba[0]; primary_lca[0][1] = primary_lca[0][5] = primary_lca[1][9] = primary_lca[1][13] = ret_rgba[1]; primary_lca[0][2] = primary_lca[0][6] = primary_lca[1][10] = primary_lca[1][14] = ret_rgba[2]; primary_lca[0][3] = primary_lca[0][7] = primary_lca[1][11] = primary_lca[1][15] = ret_rgba[3]; primary_lca[1][0] = primary_lca[1][4] = primary_lca[0][8] = primary_lca[0][12] = ret_dark_rgba[0]; primary_lca[1][1] = primary_lca[1][5] = primary_lca[0][9] = primary_lca[0][13] = ret_dark_rgba[1]; primary_lca[1][2] = primary_lca[1][6] = primary_lca[0][10] = primary_lca[0][14] = ret_dark_rgba[2]; primary_lca[1][3] = primary_lca[1][7] = primary_lca[0][11] = primary_lca[0][15] = ret_dark_rgba[3]; glPushMatrix(); glTranslatef((grd_curcanv->cv_bitmap.bm_w/2+grd_curcanv->cv_bitmap.bm_x)/(float)last_width,1.0-(grd_curcanv->cv_bitmap.bm_h/2+grd_curcanv->cv_bitmap.bm_y)/(float)last_height,0); if (scale >= 1) { size/=scale; glScalef(f2glf(size),f2glf(size*scale),f2glf(size)); } else { size*=scale; glScalef(f2glf(size/scale),f2glf(size),f2glf(size)); } glLineWidth(linedotscale*2); OGL_DISABLE(TEXTURE_2D); glDisable(GL_CULL_FACE); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); //cross if(cross) glColorPointer(4, GL_FLOAT, 0, cross_lca); else glColorPointer(4, GL_FLOAT, 0, dark_lca); glVertexPointer(2, GL_FLOAT, 0, cross_lva); glDrawArrays(GL_LINES, 0, 8); //left primary bar if(primary == 0) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, primary_lca[0]); glVertexPointer(2, GL_FLOAT, 0, primary_lva[0]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if(primary != 2) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, primary_lca[1]); glVertexPointer(2, GL_FLOAT, 0, primary_lva[1]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); //right primary bar if(primary == 0) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, primary_lca[0]); glVertexPointer(2, GL_FLOAT, 0, primary_lva[2]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if(primary != 2) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, primary_lca[1]); glVertexPointer(2, GL_FLOAT, 0, primary_lva[3]); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (secondary<=2){ //left secondary if (secondary != 1) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, bright_lca); if(!secondary_lva[0]) secondary_lva[0] = circle_array_init_2(16, 2.0, -10.0, 2.0, -2.0); ogl_drawcircle(16, GL_LINE_LOOP, secondary_lva[0]); //right secondary if (secondary != 2) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, bright_lca); if(!secondary_lva[1]) secondary_lva[1] = circle_array_init_2(16, 2.0, 10.0, 2.0, -2.0); ogl_drawcircle(16, GL_LINE_LOOP, secondary_lva[1]); } else { //bottom/middle secondary if (secondary != 4) glColorPointer(4, GL_FLOAT, 0, dark_lca); else glColorPointer(4, GL_FLOAT, 0, bright_lca); if(!secondary_lva[2]) secondary_lva[2] = circle_array_init_2(16, 2.0, 0.0, 2.0, -8.0); ogl_drawcircle(16, GL_LINE_LOOP, secondary_lva[2]); } //glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glPopMatrix(); glLineWidth(linedotscale); } /* * Stars on heaven in exit sequence, automap objects */ int g3_draw_sphere(g3s_point *pnt,fix rad){ int c=grd_curcanv->cv_color, i; float scale = ((float)grd_curcanv->cv_bitmap.bm_w/grd_curcanv->cv_bitmap.bm_h); GLfloat color_array[20*4]; for (i = 0; i < 20*4; i += 4) { color_array[i] = CPAL2Tr(c); color_array[i+1] = CPAL2Tg(c); color_array[i+2] = CPAL2Tb(c); color_array[i+3] = 1.0; } OGL_DISABLE(TEXTURE_2D); glDisable(GL_CULL_FACE); glPushMatrix(); glTranslatef(f2glf(pnt->p3_vec.x),f2glf(pnt->p3_vec.y),-f2glf(pnt->p3_vec.z)); if (scale >= 1) { rad/=scale; glScalef(f2glf(rad),f2glf(rad*scale),f2glf(rad)); } else { rad*=scale; glScalef(f2glf(rad/scale),f2glf(rad),f2glf(rad)); } if(!sphere_va) sphere_va = circle_array_init(20); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, 0, color_array); ogl_drawcircle(20, GL_TRIANGLE_FAN, sphere_va); glDisableClientState(GL_COLOR_ARRAY); glPopMatrix(); return 0; } int gr_ucircle(fix xc1, fix yc1, fix r1) { int c, nsides; c=grd_curcanv->cv_color; OGL_DISABLE(TEXTURE_2D); glColor4f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c),(grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); glPushMatrix(); glTranslatef( (f2fl(xc1) + grd_curcanv->cv_bitmap.bm_x + 0.5) / (float)last_width, 1.0 - (f2fl(yc1) + grd_curcanv->cv_bitmap.bm_y + 0.5) / (float)last_height,0); glScalef(f2fl(r1) / last_width, f2fl(r1) / last_height, 1.0); nsides = 10 + 2 * (int)(M_PI * f2fl(r1) / 19); if(!circle_va) circle_va = circle_array_init(nsides); ogl_drawcircle(nsides, GL_LINE_LOOP, circle_va); glPopMatrix(); return 0; } int gr_circle(fix xc1,fix yc1,fix r1){ return gr_ucircle(xc1,yc1,r1); } int gr_disk(fix x,fix y,fix r) { int c, nsides; c=grd_curcanv->cv_color; OGL_DISABLE(TEXTURE_2D); glColor4f(CPAL2Tr(c),CPAL2Tg(c),CPAL2Tb(c),(grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); glPushMatrix(); glTranslatef( (f2fl(x) + grd_curcanv->cv_bitmap.bm_x + 0.5) / (float)last_width, 1.0 - (f2fl(y) + grd_curcanv->cv_bitmap.bm_y + 0.5) / (float)last_height,0); glScalef(f2fl(r) / last_width, f2fl(r) / last_height, 1.0); nsides = 10 + 2 * (int)(M_PI * f2fl(r) / 19); if(!disk_va) disk_va = circle_array_init(nsides); ogl_drawcircle(nsides, GL_TRIANGLE_FAN, disk_va); glPopMatrix(); return 0; } /* * Draw flat-shaded Polygon (Lasers, Drone-arms, Driller-ears) */ bool g3_draw_poly(int nv,g3s_point **pointlist) { int c, index3, index4; float color_r, color_g, color_b, color_a; GLfloat *vertex_array, *color_array; MALLOC(vertex_array, GLfloat, nv*3); MALLOC(color_array, GLfloat, nv*4); r_polyc++; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); c = grd_curcanv->cv_color; OGL_DISABLE(TEXTURE_2D); color_r = PAL2Tr(c); color_g = PAL2Tg(c); color_b = PAL2Tb(c); if (grd_curcanv->cv_fade_level >= GR_FADE_OFF) color_a = 1.0; else color_a = 1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0); for (c=0; cp3_vec.x); vertex_array[index3+1] = f2glf(pointlist[c]->p3_vec.y); vertex_array[index3+2] = -f2glf(pointlist[c]->p3_vec.z); } glVertexPointer(3, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glDrawArrays(GL_TRIANGLE_FAN, 0, nv); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); d_free(vertex_array); d_free(color_array); return 0; } void gr_upoly_tmap(int nverts, int *vert ){ glmprintf((0,"gr_upoly_tmap: unhandled\n"));//should never get called } void draw_tmap_flat(grs_bitmap *bm,int nv,g3s_point **vertlist){ glmprintf((0,"draw_tmap_flat: unhandled\n"));//should never get called } extern void (*tmap_drawer_ptr)(grs_bitmap *bm,int nv,g3s_point **vertlist); /* * Everything texturemapped (walls, robots, ship) */ bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm) { int c, index2, index3, index4; GLfloat *vertex_array, *color_array, *texcoord_array, color_alpha = 1.0; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); if (tmap_drawer_ptr == draw_tmap) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); OGL_ENABLE(TEXTURE_2D); ogl_bindbmtex(bm); ogl_texwrap(bm->gltexture, GL_REPEAT); r_tpolyc++; color_alpha = (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:(1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); } else if (tmap_drawer_ptr == draw_tmap_flat) { OGL_DISABLE(TEXTURE_2D); /* for cloaked state faces */ color_alpha = 1.0 - (grd_curcanv->cv_fade_level/(GLfloat)NUM_LIGHTING_LEVELS); } else { glmprintf((0,"g3_draw_tmap: unhandled tmap_drawer %p\n",tmap_drawer_ptr)); return 0; } MALLOC(vertex_array, GLfloat, nv*3); MALLOC(color_array, GLfloat, nv*4); MALLOC(texcoord_array, GLfloat, nv*2); for (c=0; cp3_vec.x); vertex_array[index3+1] = f2glf(pointlist[c]->p3_vec.y); vertex_array[index3+2] = -f2glf(pointlist[c]->p3_vec.z); if (tmap_drawer_ptr == draw_tmap_flat) { color_array[index4] = 0; color_array[index4+1] = color_array[index4]; color_array[index4+2] = color_array[index4]; color_array[index4+3] = color_alpha; } else { color_array[index4] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].r); color_array[index4+1] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].g); color_array[index4+2] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].b); color_array[index4+3] = color_alpha; } texcoord_array[index2] = f2glf(uvl_list[c].u); texcoord_array[index2+1] = f2glf(uvl_list[c].v); } glVertexPointer(3, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); if (tmap_drawer_ptr == draw_tmap) { glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array); } glDrawArrays(GL_TRIANGLE_FAN, 0, nv); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); d_free(vertex_array); d_free(color_array); d_free(texcoord_array); return 0; } /* * Everything texturemapped with secondary texture (walls with secondary texture) */ bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, g3s_lrgb *light_rgb, grs_bitmap *bmbot, grs_bitmap *bm, int orient) { int c, index2, index3, index4; GLfloat *vertex_array, *color_array, *texcoord_array; MALLOC(vertex_array, GLfloat, nv*3); MALLOC(color_array, GLfloat, nv*4); MALLOC(texcoord_array, GLfloat, nv*2); g3_draw_tmap(nv,pointlist,uvl_list,light_rgb,bmbot);//draw the bottom texture first.. could be optimized with multitexturing.. glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); r_tpolyc++; OGL_ENABLE(TEXTURE_2D); ogl_bindbmtex(bm); ogl_texwrap(bm->gltexture,GL_REPEAT); for (c=0; cbm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].r); color_array[index4+1] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].g); color_array[index4+2] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].b); color_array[index4+3] = (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:(1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); vertex_array[index3] = f2glf(pointlist[c]->p3_vec.x); vertex_array[index3+1] = f2glf(pointlist[c]->p3_vec.y); vertex_array[index3+2] = -f2glf(pointlist[c]->p3_vec.z); } glVertexPointer(3, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array); glDrawArrays(GL_TRIANGLE_FAN, 0, nv); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); d_free(vertex_array); d_free(color_array); d_free(texcoord_array); return 0; } /* * 2d Sprites (Fireaballs, powerups, explosions). NOT hostages */ bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm) { vms_vector pv,v1; int i; GLfloat vertex_array[12], color_array[16], texcoord_array[8]; r_bitmapc++; v1.z=0; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); OGL_ENABLE(TEXTURE_2D); ogl_bindbmtex(bm); ogl_texwrap(bm->gltexture,GL_CLAMP_TO_EDGE); width = fixmul(width,Matrix_scale.x); height = fixmul(height,Matrix_scale.y); for (i=0;i<4;i++){ vm_vec_sub(&v1,pos,&View_position); vm_vec_rotate(&pv,&v1,&View_matrix); switch (i){ case 0: texcoord_array[i*2] = 0.0; texcoord_array[i*2+1] = 0.0; pv.x+=-width; pv.y+=height; break; case 1: texcoord_array[i*2] = bm->gltexture->u; texcoord_array[i*2+1] = 0.0; pv.x+=width; pv.y+=height; break; case 2: texcoord_array[i*2] = bm->gltexture->u; texcoord_array[i*2+1] = bm->gltexture->v; pv.x+=width; pv.y+=-height; break; case 3: texcoord_array[i*2] = 0.0; texcoord_array[i*2+1] = bm->gltexture->v; pv.x+=-width; pv.y+=-height; break; } color_array[i*4] = 1.0; color_array[i*4+1] = 1.0; color_array[i*4+2] = 1.0; color_array[i*4+3] = (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:(1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); vertex_array[i*3] = f2glf(pv.x); vertex_array[i*3+1] = f2glf(pv.y); vertex_array[i*3+2] = -f2glf(pv.z); } glVertexPointer(3, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); // Replaced GL_QUADS glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); return 0; } /* * Movies * Since this function will create a new texture each call, mipmapping can be very GPU intensive - so it has an optional setting for texture filtering. */ bool ogl_ubitblt_i(int dw,int dh,int dx,int dy, int sw, int sh, int sx, int sy, grs_bitmap * src, grs_bitmap * dest, int texfilt) { GLfloat xo,yo,xs,ys,u1,v1; GLfloat color_array[] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; GLfloat texcoord_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; GLfloat vertex_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; ogl_texture tex; r_ubitbltc++; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); ogl_init_texture(&tex, sw, sh, OGL_FLAG_ALPHA); tex.prio = 0.0; tex.lw=src->bm_rowsize; u1=v1=0; dx+=dest->bm_x; dy+=dest->bm_y; xo=dx/(float)last_width; xs=dw/(float)last_width; yo=1.0-dy/(float)last_height; ys=dh/(float)last_height; OGL_ENABLE(TEXTURE_2D); ogl_pal=gr_current_pal; ogl_loadtexture(src->bm_data, sx, sy, &tex, src->bm_flags, 0, texfilt); ogl_pal=gr_palette; OGL_BINDTEXTURE(tex.handle); ogl_texwrap(&tex,GL_CLAMP_TO_EDGE); vertex_array[0] = xo; vertex_array[1] = yo; vertex_array[2] = xo+xs; vertex_array[3] = yo; vertex_array[4] = xo+xs; vertex_array[5] = yo-ys; vertex_array[6] = xo; vertex_array[7] = yo-ys; texcoord_array[0] = u1; texcoord_array[1] = v1; texcoord_array[2] = tex.u; texcoord_array[3] = v1; texcoord_array[4] = tex.u; texcoord_array[5] = tex.v; texcoord_array[6] = u1; texcoord_array[7] = tex.v; glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); ogl_freetexture(&tex); return 0; } bool ogl_ubitblt(int w,int h,int dx,int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest){ return ogl_ubitblt_i(w,h,dx,dy,w,h,sx,sy,src,dest,0); } /* * set depth testing on or off */ void ogl_toggle_depth_test(int enable) { if (enable) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); } /* * set blending function */ void ogl_set_blending() { switch ( grd_curcanv->cv_blend_func ) { case GR_BLEND_ADDITIVE_A: glBlendFunc( GL_SRC_ALPHA, GL_ONE ); break; case GR_BLEND_ADDITIVE_C: glBlendFunc( GL_ONE, GL_ONE ); break; case GR_BLEND_NORMAL: default: glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); break; } } GLubyte *pixels = NULL; void ogl_start_frame(void){ r_polyc=0;r_tpolyc=0;r_bitmapc=0;r_ubitbltc=0;r_upixelc=0; OGL_VIEWPORT(grd_curcanv->cv_bitmap.bm_x,grd_curcanv->cv_bitmap.bm_y,Canvas_width,Canvas_height); glClearColor(0.0, 0.0, 0.0, 0.0); glLineWidth(linedotscale); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL,0.02); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glShadeModel(GL_SMOOTH); glMatrixMode(GL_PROJECTION); glLoadIdentity();//clear matrix #ifdef OGLES perspective(90.0,1.0,0.1,5000.0); #else gluPerspective(90.0,1.0,0.1,5000.0); #endif glMatrixMode(GL_MODELVIEW); glLoadIdentity();//clear matrix } void ogl_end_frame(void){ OGL_VIEWPORT(0,0,grd_curscreen->sc_w,grd_curscreen->sc_h); glMatrixMode(GL_PROJECTION); glLoadIdentity();//clear matrix #ifdef OGLES glOrthof(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); #else glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); #endif glMatrixMode(GL_MODELVIEW); glLoadIdentity();//clear matrix glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); } void gr_flip(void) { if (GameArg.DbgRenderStats) ogl_texture_stats(); ogl_do_palfx(); ogl_swap_buffers_internal(); glClear(GL_COLOR_BUFFER_BIT); } int tex_format_supported(int iformat,int format) { #ifndef OGLES switch (iformat){ case GL_INTENSITY4: if (!GameArg.DbgGlIntensity4Ok) return 0; break; case GL_LUMINANCE4_ALPHA4: if (!GameArg.DbgGlLuminance4Alpha4Ok) return 0; break; case GL_RGBA2: if (!GameArg.DbgGlRGBA2Ok) return 0; break; } if (GameArg.DbgGlGetTexLevelParamOk){ GLint internalFormat; glTexImage2D(GL_PROXY_TEXTURE_2D, 0, iformat, 64, 64, 0, format, GL_UNSIGNED_BYTE, texbuf);//NULL? glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); return (internalFormat==iformat); }else #endif return 1; } //little hack to find the nearest bigger power of 2 for a given number int pow2ize(int x){ int i; for (i=2; i max(grd_curscreen->sc_w, 1024)) || (height > max(grd_curscreen->sc_h, 256))) Error("Texture is too big: %ix%i", width, height); i=0; for (y=0;yinternalformat,tex->format)){ glmprintf((0,"tex format %x not supported",tex->internalformat)); switch (tex->internalformat){ #ifdef OGLES case GL_RGB: tex->format=GL_RGB; break; case GL_RGBA: tex->format=GL_RGBA; #else case GL_INTENSITY4: if (GameArg.DbgGlLuminance4Alpha4Ok){ tex->internalformat=GL_LUMINANCE4_ALPHA4; tex->format=GL_LUMINANCE_ALPHA; break; }//note how it will fall through here if the statement is false case GL_LUMINANCE4_ALPHA4: if (GameArg.DbgGlRGBA2Ok){ tex->internalformat=GL_RGBA2; tex->format=GL_RGBA; break; }//note how it will fall through here if the statement is false case GL_RGBA2: #if defined(__APPLE__) && defined(__MACH__) case GL_RGB8: // Quartz doesn't support RGB only #endif tex->internalformat = ogl_rgba_internalformat; tex->format=GL_RGBA; break; #endif // OGLES default: glmprintf((0,"...no tex format to fall back on\n")); return 1; } glmprintf((0,"...falling back to %x\n",tex->internalformat)); } return 0; } void tex_set_size1(ogl_texture *tex,int dbits,int bits,int w, int h){ int u; if (tex->tw!=w || tex->th!=h){ u=(tex->w/(float)tex->tw*w) * (tex->h/(float)tex->th*h); glmprintf((0,"shrunken texture?\n")); }else u=tex->w*tex->h; if (bits<=0){//the beta nvidia GLX server. doesn't ever return any bit sizes, so just use some assumptions. tex->bytes=((float)w*h*dbits)/8.0; tex->bytesu=((float)u*dbits)/8.0; }else{ tex->bytes=((float)w*h*bits)/8.0; tex->bytesu=((float)u*bits)/8.0; } glmprintf((0,"tex_set_size1: %ix%i, %ib(%i) %iB\n",w,h,bits,dbits,tex->bytes)); } void tex_set_size(ogl_texture *tex){ GLint w,h; int bi=16,a=0; #ifndef OGLES if (GameArg.DbgGlGetTexLevelParamOk){ GLint t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&w); glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&h); glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_LUMINANCE_SIZE,&t);a+=t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_INTENSITY_SIZE,&t);a+=t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_RED_SIZE,&t);a+=t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_GREEN_SIZE,&t);a+=t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_BLUE_SIZE,&t);a+=t; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_ALPHA_SIZE,&t);a+=t; } else #endif { w=tex->tw; h=tex->th; } switch (tex->format){ case GL_LUMINANCE: bi=8; break; case GL_LUMINANCE_ALPHA: bi=8; break; case GL_RGB: case GL_RGBA: bi=16; break; #ifndef OGLES case GL_COLOR_INDEX: bi = 8; break; #endif default: Error("tex_set_size unknown texformat\n"); break; } tex_set_size1(tex,bi,a,w,h); } //loads a palettized bitmap into a ogl RGBA texture. //Sizes and pads dimensions to multiples of 2 if necessary. //In theory this could be a problem for repeating textures, but all real //textures (not sprites, etc) in descent are 64x64, so we are ok. //stores OpenGL textured id in *texid and u/v values required to get only the real data in *u/*v int ogl_loadtexture (unsigned char *data, int dxo, int dyo, ogl_texture *tex, int bm_flags, int data_format, int texfilt) { GLubyte *bufP = texbuf; tex->tw = pow2ize (tex->w); tex->th = pow2ize (tex->h);//calculate smallest texture size that can accomodate us (must be multiples of 2) //calculate u/v values that would make the resulting texture correctly sized tex->u = (float) ((double) tex->w / (double) tex->tw); tex->v = (float) ((double) tex->h / (double) tex->th); if (data) { if (bm_flags >= 0) ogl_filltexbuf (data, texbuf, tex->lw, tex->w, tex->h, dxo, dyo, tex->tw, tex->th, tex->format, bm_flags, data_format); else { if (!dxo && !dyo && (tex->w == tex->tw) && (tex->h == tex->th)) bufP = data; else { int h, w, tw; h = tex->lw / tex->w; w = (tex->w - dxo) * h; data += tex->lw * dyo + h * dxo; bufP = texbuf; tw = tex->tw * h; h = tw - w; for (; dyo < tex->h; dyo++, data += tex->lw) { memcpy (bufP, data, w); bufP += w; memset (bufP, 0, h); bufP += h; } memset (bufP, 0, tex->th * tw - (bufP - texbuf)); bufP = texbuf; } } } // Generate OpenGL texture IDs. glGenTextures (1, &tex->handle); #ifndef OGLES //set priority glPrioritizeTextures (1, &tex->handle, &tex->prio); #endif // Give our data to OpenGL. OGL_BINDTEXTURE(tex->handle); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (texfilt) { #ifdef OGLES // in OpenGL ES 1.1 the mipmaps are automatically generated by a parameter glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP, texfilt ? GL_TRUE : GL_FALSE); #endif glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (texfilt>=2?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST)); #ifndef OGLES if (texfilt >= 3 && ogl_maxanisotropy > 1.0) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ogl_maxanisotropy); #endif } else { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } #ifndef OGLES // see comment above if (texfilt) { gluBuild2DMipmaps ( GL_TEXTURE_2D, tex->internalformat, tex->tw, tex->th, tex->format, GL_UNSIGNED_BYTE, bufP); } else #endif { glTexImage2D ( GL_TEXTURE_2D, 0, tex->internalformat, tex->tw, tex->th, 0, tex->format, // RGBA textures. GL_UNSIGNED_BYTE, // imageData is a GLubyte pointer. bufP); } tex_set_size (tex); r_texcount++; return 0; } unsigned char decodebuf[1024*1024]; void ogl_loadbmtexture_f(grs_bitmap *bm, int texfilt) { unsigned char *buf; #ifdef HAVE_LIBPNG char *bitmapname; #endif while (bm->bm_parent) bm=bm->bm_parent; if (bm->gltexture && bm->gltexture->handle > 0) return; buf=bm->bm_data; #ifdef HAVE_LIBPNG if ((bitmapname = piggy_game_bitmap_name(bm))) { char filename[64]; png_data pdata; sprintf(filename, "textures/%s.png", bitmapname); if (read_png(filename, &pdata)) { con_printf(CON_DEBUG,"%s: %ux%ux%i p=%i(%i) c=%i a=%i chans=%i\n", filename, pdata.width, pdata.height, pdata.depth, pdata.paletted, pdata.num_palette, pdata.color, pdata.alpha, pdata.channels); if (pdata.depth == 8 && pdata.color) { if (bm->gltexture == NULL) ogl_init_texture(bm->gltexture = ogl_get_free_texture(), pdata.width, pdata.height, flags | ((pdata.alpha || bm->bm_flags & BM_FLAG_TRANSPARENT) ? OGL_FLAG_ALPHA : 0)); ogl_loadtexture(pdata.data, 0, 0, bm->gltexture, bm->bm_flags, pdata.paletted ? 0 : pdata.channels, texfilt); free(pdata.data); if (pdata.palette) free(pdata.palette); return; } else { con_printf(CON_DEBUG,"%s: unsupported texture format: must be rgb, rgba, or paletted, and depth 8\n", filename); free(pdata.data); if (pdata.palette) free(pdata.palette); } } } #endif if (bm->gltexture == NULL){ ogl_init_texture(bm->gltexture = ogl_get_free_texture(), bm->bm_w, bm->bm_h, ((bm->bm_flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT))? OGL_FLAG_ALPHA : 0)); } else { if (bm->gltexture->handle>0) return; if (bm->gltexture->w==0){ bm->gltexture->lw=bm->bm_w; bm->gltexture->w=bm->bm_w; bm->gltexture->h=bm->bm_h; } } if (bm->bm_flags & BM_FLAG_RLE){ unsigned char * dbits; unsigned char * sbits; int i, data_offset; data_offset = 1; if (bm->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)]; dbits = decodebuf; for (i=0; i < bm->bm_h; i++ ) { gr_rle_decode(sbits,dbits); if ( bm->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)]))); else sbits += (int)bm->bm_data[4+i]; dbits += bm->bm_w; } buf=decodebuf; } ogl_loadtexture(buf, 0, 0, bm->gltexture, bm->bm_flags, 0, texfilt); } void ogl_loadbmtexture(grs_bitmap *bm) { ogl_loadbmtexture_f(bm, GameCfg.TexFilt); } void ogl_freetexture(ogl_texture *gltexture) { if (gltexture->handle>0) { r_texcount--; glmprintf((0,"ogl_freetexture(%p):%i (%i left)\n",gltexture,gltexture->handle,r_texcount)); glDeleteTextures( 1, &gltexture->handle ); // gltexture->handle=0; ogl_reset_texture(gltexture); } } void ogl_freebmtexture(grs_bitmap *bm){ if (bm->gltexture){ ogl_freetexture(bm->gltexture); bm->gltexture=NULL; } } /* * Menu / gauges */ bool ogl_ubitmapm_cs(int x, int y,int dw, int dh, grs_bitmap *bm,int c, int scale) // to scale bitmaps { GLfloat xo,yo,xf,yf,u1,u2,v1,v2,color_r,color_g,color_b,h; GLfloat color_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; GLfloat texcoord_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; GLfloat vertex_array[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; x+=grd_curcanv->cv_bitmap.bm_x; y+=grd_curcanv->cv_bitmap.bm_y; xo=x/(float)last_width; xf=(bm->bm_w+x)/(float)last_width; yo=1.0-y/(float)last_height; yf=1.0-(bm->bm_h+y)/(float)last_height; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (dw < 0) dw = grd_curcanv->cv_bitmap.bm_w; else if (dw == 0) dw = bm->bm_w; if (dh < 0) dh = grd_curcanv->cv_bitmap.bm_h; else if (dh == 0) dh = bm->bm_h; h = (double) scale / (double) F1_0; xo = x / ((double) last_width * h); xf = (dw + x) / ((double) last_width * h); yo = 1.0 - y / ((double) last_height * h); yf = 1.0 - (dh + y) / ((double) last_height * h); OGL_ENABLE(TEXTURE_2D); ogl_bindbmtex(bm); ogl_texwrap(bm->gltexture,GL_CLAMP_TO_EDGE); if (bm->bm_x==0){ u1=0; if (bm->bm_w==bm->gltexture->w) u2=bm->gltexture->u; else u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw; }else { u1=bm->bm_x/(float)bm->gltexture->tw; u2=(bm->bm_w+bm->bm_x)/(float)bm->gltexture->tw; } if (bm->bm_y==0){ v1=0; if (bm->bm_h==bm->gltexture->h) v2=bm->gltexture->v; else v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th; }else{ v1=bm->bm_y/(float)bm->gltexture->th; v2=(bm->bm_h+bm->bm_y)/(float)bm->gltexture->th; } if (c < 0) { color_r = 1.0; color_g = 1.0; color_b = 1.0; } else { color_r = CPAL2Tr(c); color_g = CPAL2Tg(c); color_b = CPAL2Tb(c); } color_array[0] = color_array[4] = color_array[8] = color_array[12] = color_r; color_array[1] = color_array[5] = color_array[9] = color_array[13] = color_g; color_array[2] = color_array[6] = color_array[10] = color_array[14] = color_b; color_array[3] = color_array[7] = color_array[11] = color_array[15] = 1.0; vertex_array[0] = xo; vertex_array[1] = yo; vertex_array[2] = xf; vertex_array[3] = yo; vertex_array[4] = xf; vertex_array[5] = yf; vertex_array[6] = xo; vertex_array[7] = yf; texcoord_array[0] = u1; texcoord_array[1] = v1; texcoord_array[2] = u2; texcoord_array[3] = v1; texcoord_array[4] = u2; texcoord_array[5] = v2; texcoord_array[6] = u1; texcoord_array[7] = v2; glVertexPointer(2, GL_FLOAT, 0, vertex_array); glColorPointer(4, GL_FLOAT, 0, color_array); glTexCoordPointer(2, GL_FLOAT, 0, texcoord_array); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); return 0; } dxx-rebirth-0.58.1-d1x/arch/sdl/000077500000000000000000000000001217717257200162515ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/sdl/digi.c000066400000000000000000000122641217717257200173360ustar00rootroot00000000000000/* * Digital audio support * Library-independent stub for dynamic selection of sound system */ #include "pstypes.h" #include "dxxerror.h" #include "fix.h" #include "vecmat.h" #include "gr.h" #include "piggy.h" #include "digi.h" #include "sounds.h" #include "wall.h" #include "newdemo.h" #include "kconfig.h" #include "console.h" #include "rbaudio.h" #include "jukebox.h" #include #include #include #include #include #ifdef USE_SDLMIXER #include #endif #ifdef _WIN32 #include "hmp.h" #endif /* Sound system function pointers */ int (*fptr_init)() = NULL; void (*fptr_close)() = NULL; void (*fptr_reset)() = NULL; void (*fptr_set_channel_volume)(int, int) = NULL; void (*fptr_set_channel_pan)(int, int) = NULL; int (*fptr_start_sound)(short, fix, int, int, int, int, int) = NULL; void (*fptr_stop_sound)(int) = NULL; void (*fptr_end_sound)(int) = NULL; int (*fptr_is_sound_playing)(int) = NULL; int (*fptr_is_channel_playing)(int) = NULL; void (*fptr_stop_all_channels)() = NULL; void (*fptr_set_digi_volume)(int) = NULL; void digi_select_system(int n) { switch (n) { #ifdef USE_SDLMIXER case SDLMIXER_SYSTEM: con_printf(CON_NORMAL,"Using SDL_mixer library\n"); fptr_init = digi_mixer_init; fptr_close = digi_mixer_close; fptr_reset = digi_mixer_reset; fptr_set_channel_volume = digi_mixer_set_channel_volume; fptr_set_channel_pan = digi_mixer_set_channel_pan; fptr_start_sound = digi_mixer_start_sound; fptr_stop_sound = digi_mixer_stop_sound; fptr_end_sound = digi_mixer_end_sound; fptr_is_sound_playing = digi_mixer_is_sound_playing; fptr_is_channel_playing = digi_mixer_is_channel_playing; fptr_stop_all_channels = digi_mixer_stop_all_channels; fptr_set_digi_volume = digi_mixer_set_digi_volume; break; #endif case SDLAUDIO_SYSTEM: default: con_printf(CON_NORMAL,"Using plain old SDL audio\n"); fptr_init = digi_audio_init; fptr_close = digi_audio_close; fptr_reset = digi_audio_reset; fptr_set_channel_volume = digi_audio_set_channel_volume; fptr_set_channel_pan = digi_audio_set_channel_pan; fptr_start_sound = digi_audio_start_sound; fptr_stop_sound = digi_audio_stop_sound; fptr_end_sound = digi_audio_end_sound; fptr_is_sound_playing = digi_audio_is_sound_playing; fptr_is_channel_playing = digi_audio_is_channel_playing; fptr_stop_all_channels = digi_audio_stop_all_channels; fptr_set_digi_volume = digi_audio_set_digi_volume; break; } } /* Common digi functions */ #ifndef NDEBUG static int digi_initialised = 0; #endif extern int digi_max_channels; int digi_sample_rate = SAMPLE_RATE_11K; int digi_volume = SOUND_MAX_VOLUME; void digi_set_volume(int dvolume) { digi_volume = dvolume; if (fptr_set_digi_volume) digi_set_digi_volume(dvolume); } void digi_set_sample_rate(int r) { digi_sample_rate = r; } /* Stub functions */ int digi_init() { digi_init_sounds(); return fptr_init(); } void digi_close() { fptr_close(); } void digi_reset() { fptr_reset(); } void digi_set_channel_volume(int channel, int volume) { fptr_set_channel_volume(channel, volume); } void digi_set_channel_pan(int channel, int pan) { fptr_set_channel_pan(channel, pan); } int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) { return fptr_start_sound(soundnum, volume, pan, looping, loop_start, loop_end, soundobj); } void digi_stop_sound(int channel) { fptr_stop_sound(channel); } void digi_end_sound(int channel) { fptr_end_sound(channel); } int digi_is_sound_playing(int soundno) { return fptr_is_sound_playing(soundno); } int digi_is_channel_playing(int channel) { return fptr_is_channel_playing(channel); } void digi_stop_all_channels() { fptr_stop_all_channels(); } void digi_set_digi_volume(int dvolume) { fptr_set_digi_volume(dvolume); } #ifndef NDEBUG void digi_debug() { int i; int n_voices = 0; if (!digi_initialised) return; for (i = 0; i < digi_max_channels; i++) { if (digi_is_channel_playing(i)) n_voices++; } } #endif #ifdef _WIN32 // Windows native-MIDI stuff. int digi_win32_midi_song_playing=0; static hmp_file *cur_hmp=NULL; static int firstplay = 1; void digi_win32_set_midi_volume( int mvolume ) { hmp_setvolume(cur_hmp, mvolume*MIDI_VOLUME_SCALE/8); } int digi_win32_play_midi_song( char * filename, int loop ) { if (firstplay) { hmp_reset(); firstplay = 0; } digi_win32_stop_midi_song(); if (filename == NULL) return 0; if ((cur_hmp = hmp_open(filename))) { /* * FIXME: to be implemented as soon as we have some kind or checksum function - replacement for ugly hack in hmp.c for descent.hmp * if (***filesize check*** && ***CRC32 or MD5 check***) * (((*cur_hmp).trks)[1]).data[6] = 0x6C; */ if (hmp_play(cur_hmp,loop) != 0) return 0; // error digi_win32_midi_song_playing = 1; digi_win32_set_midi_volume(GameCfg.MusicVolume); return 1; } return 0; } void digi_win32_pause_midi_song() { hmp_pause(cur_hmp); } void digi_win32_resume_midi_song() { hmp_resume(cur_hmp); } void digi_win32_stop_midi_song() { if (!digi_win32_midi_song_playing) return; hmp_close(cur_hmp); cur_hmp = NULL; digi_win32_midi_song_playing = 0; hmp_reset(); } #endif dxx-rebirth-0.58.1-d1x/arch/sdl/digi_audio.c000066400000000000000000000262131217717257200205160ustar00rootroot00000000000000/* * * SDL digital audio support * * */ #include #include #include #include #include #include "pstypes.h" #include "dxxerror.h" #include "fix.h" #include "vecmat.h" #include "gr.h" #include "piggy.h" #include "digi.h" #include "sounds.h" #include "wall.h" #include "newdemo.h" #include "kconfig.h" #include "config.h" //changed on 980905 by adb to increase number of concurrent sounds #define MAX_SOUND_SLOTS 32 //end changes by adb #define SOUND_BUFFER_SIZE 1024 #define MIN_VOLUME 10 /* This table is used to add two sound values together and pin * the value to avoid overflow. (used with permission from ARDI) * DPH: Taken from SDL/src/SDL_mixer.c. */ static const Uint8 mix8[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static int digi_initialised = 0; struct sound_slot { int soundno; int playing; // Is there a sample playing on this channel? int looped; // Play this sample looped? fix pan; // 0 = far left, 1 = far right fix volume; // 0 = nothing, 1 = fully on //changed on 980905 by adb from char * to unsigned char * unsigned char *samples; //end changes by adb unsigned int length; // Length of the sample unsigned int position; // Position we are at at the moment. int soundobj; // Which soundobject is on this channel int persistent; // This can't be pre-empted } SoundSlots[MAX_SOUND_SLOTS]; static SDL_AudioSpec WaveSpec; int digi_max_channels = 16; static int next_channel = 0; void digi_stop_sound(int channel); int digi_xlat_sound(int soundno); /* Audio mixing callback */ //changed on 980905 by adb to cleanup, add pan support and optimize mixer static void audio_mixcallback(void *userdata, Uint8 *stream, int len) { Uint8 *streamend = stream + len; struct sound_slot *sl; if (!digi_initialised) return; memset(stream, 0x80, len); // fix "static" sound bug on Mac OS X SDL_LockAudio(); for (sl = SoundSlots; sl < SoundSlots + MAX_SOUND_SLOTS; sl++) { if (sl->playing) { Uint8 *sldata = sl->samples + sl->position, *slend = sl->samples + sl->length; Uint8 *sp = stream, s; signed char v; fix vl, vr; int x; if ((x = sl->pan) & 0x8000) { vl = 0x20000 - x * 2; vr = 0x10000; } else { vl = 0x10000; vr = x * 2; } vl = fixmul(vl, (x = sl->volume)); vr = fixmul(vr, x); while (sp < streamend) { if (sldata == slend) { if (!sl->looped) { sl->playing = 0; break; } sldata = sl->samples; } v = *(sldata++) - 0x80; s = *sp; *(sp++) = mix8[ s + fixmul(v, vl) + 0x80 ]; s = *sp; *(sp++) = mix8[ s + fixmul(v, vr) + 0x80 ]; } sl->position = sldata - sl->samples; } } SDL_UnlockAudio(); } //end changes by adb /* Initialise audio devices. */ int digi_audio_init() { if (SDL_InitSubSystem(SDL_INIT_AUDIO)<0) { Error("SDL audio initialisation failed: %s.",SDL_GetError()); } WaveSpec.freq = digi_sample_rate; //added/changed by Sam Lantinga on 12/01/98 for new SDL version WaveSpec.format = AUDIO_U8; WaveSpec.channels = 2; //end this section addition/change - SL WaveSpec.samples = SOUND_BUFFER_SIZE; WaveSpec.callback = audio_mixcallback; if ( SDL_OpenAudio(&WaveSpec, NULL) < 0 ) { //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound. Warning("\nError: Couldn't open audio: %s\n", SDL_GetError()); //killed exit(2); return 1; //end edit -MM } SDL_PauseAudio(0); digi_initialised = 1; digi_audio_set_digi_volume( (GameCfg.DigiVolume*32768)/8 ); return 0; } /* Toggle audio */ void digi_audio_reset() { } /* Shut down audio */ void digi_audio_close() { if (!digi_initialised) return; digi_initialised = 0; #ifdef __MINGW32__ SDL_Delay(500); // CloseAudio hangs if it's called too soon after opening? #endif SDL_CloseAudio(); } void digi_audio_stop_all_channels() { int i; for (i = 0; i < MAX_SOUND_SLOTS; i++) digi_audio_stop_sound(i); } extern void digi_end_soundobj(int channel); extern int SoundQ_channel; extern void SoundQ_end(); int verify_sound_channel_free(int channel); // Volume 0-F1_0 int digi_audio_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) { int i, starting_channel; if (!digi_initialised) return -1; if (soundnum < 0) return -1; SDL_LockAudio(); Assert(GameSounds[soundnum].data != (void *)-1); starting_channel = next_channel; while(1) { if (!SoundSlots[next_channel].playing) break; if (!SoundSlots[next_channel].persistent) break; // use this channel! next_channel++; if (next_channel >= digi_max_channels) next_channel = 0; if (next_channel == starting_channel) { SDL_UnlockAudio(); return -1; } } if (SoundSlots[next_channel].playing) { SoundSlots[next_channel].playing = 0; if (SoundSlots[next_channel].soundobj > -1) { digi_end_soundobj(SoundSlots[next_channel].soundobj); } if (SoundQ_channel == next_channel) SoundQ_end(); } #ifndef NDEBUG verify_sound_channel_free(next_channel); #endif SoundSlots[next_channel].soundno = soundnum; SoundSlots[next_channel].samples = GameSounds[soundnum].data; SoundSlots[next_channel].length = GameSounds[soundnum].length; SoundSlots[next_channel].volume = fixmul(digi_volume, volume); SoundSlots[next_channel].pan = pan; SoundSlots[next_channel].position = 0; SoundSlots[next_channel].looped = looping; SoundSlots[next_channel].playing = 1; SoundSlots[next_channel].soundobj = soundobj; SoundSlots[next_channel].persistent = 0; if ((soundobj > -1) || (looping) || (volume > F1_0)) SoundSlots[next_channel].persistent = 1; i = next_channel; next_channel++; if (next_channel >= digi_max_channels) next_channel = 0; SDL_UnlockAudio(); return i; } // Returns the channel a sound number is playing on, or // -1 if none. int digi_audio_find_channel(int soundno) { if (!digi_initialised) return -1; if (soundno < 0 ) return -1; if (GameSounds[soundno].data == NULL) { Int3(); return -1; } //FIXME: not implemented return -1; } //added on 980905 by adb from original source to make sfx volume work void digi_audio_set_digi_volume( int dvolume ) { dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff); if ( dvolume > SOUND_MAX_VOLUME ) digi_volume = SOUND_MAX_VOLUME; else if ( dvolume < 0 ) digi_volume = 0; else digi_volume = dvolume; if ( !digi_initialised ) return; digi_sync_sounds(); } //end edit by adb int digi_audio_is_sound_playing(int soundno) { int i; soundno = digi_xlat_sound(soundno); for (i = 0; i < MAX_SOUND_SLOTS; i++) //changed on 980905 by adb: added SoundSlots[i].playing && if (SoundSlots[i].playing && SoundSlots[i].soundno == soundno) //end changes by adb return 1; return 0; } //added on 980905 by adb to make sound channel setting work void digi_audio_set_max_channels(int n) { digi_max_channels = n; if ( digi_max_channels < 1 ) digi_max_channels = 1; if (digi_max_channels > MAX_SOUND_SLOTS) digi_max_channels = MAX_SOUND_SLOTS; if ( !digi_initialised ) return; digi_stop_all_channels(); } int digi_audio_get_max_channels() { return digi_max_channels; } // end edit by adb int digi_audio_is_channel_playing(int channel) { if (!digi_initialised) return 0; return SoundSlots[channel].playing; } void digi_audio_set_channel_volume(int channel, int volume) { if (!digi_initialised) return; if (!SoundSlots[channel].playing) return; SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0); } void digi_audio_set_channel_pan(int channel, int pan) { if (!digi_initialised) return; if (!SoundSlots[channel].playing) return; SoundSlots[channel].pan = pan; } void digi_audio_stop_sound(int channel) { SoundSlots[channel].playing=0; SoundSlots[channel].soundobj = -1; SoundSlots[channel].persistent = 0; } void digi_audio_end_sound(int channel) { if (!digi_initialised) return; if (!SoundSlots[channel].playing) return; SoundSlots[channel].soundobj = -1; SoundSlots[channel].persistent = 0; } #ifndef NDEBUG void digi_audio_debug() { int i; int n_voices = 0; if (!digi_initialised) return; for (i = 0; i < digi_max_channels; i++) { if (digi_is_channel_playing(i)) n_voices++; } } #endif dxx-rebirth-0.58.1-d1x/arch/sdl/digi_mixer.c000066400000000000000000000130161217717257200205360ustar00rootroot00000000000000/* * This is an alternate backend for the sound effect system. * It uses SDL_mixer to provide a more reliable playback, * and allow processing of multiple audio formats. * * This file is based on the original D1X arch/sdl/digi.c * * -- MD2211 (2006-10-12) */ #include #include #include #include #include #if !(defined(__APPLE__) && defined(__MACH__)) #include #else #include #endif #include "pstypes.h" #include "dxxerror.h" #include "sounds.h" #include "digi.h" #include "digi_mixer.h" #include "digi_mixer_music.h" #include "console.h" #include "config.h" #include "args.h" #include "fix.h" #include "gr.h" // needed for piggy.h #include "piggy.h" #define MIX_DIGI_DEBUG 0 #define MIX_OUTPUT_FORMAT AUDIO_S16 #define MIX_OUTPUT_CHANNELS 2 #define MAX_SOUND_SLOTS 64 #if !((defined(__APPLE__) && defined(__MACH__)) || defined(macintosh)) #define SOUND_BUFFER_SIZE 2048 #else #define SOUND_BUFFER_SIZE 1024 #endif #define MIN_VOLUME 10 static int digi_initialised = 0; static int digi_max_channels = MAX_SOUND_SLOTS; static inline int fix2byte(fix f) { return (f / 256) % 256; } Mix_Chunk SoundChunks[MAX_SOUNDS]; ubyte channels[MAX_SOUND_SLOTS]; /* Initialise audio */ int digi_mixer_init() { digi_sample_rate = SAMPLE_RATE_44K; if (MIX_DIGI_DEBUG) con_printf(CON_DEBUG,"digi_init %d (SDL_Mixer)\n", MAX_SOUNDS); if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) Error("SDL audio initialisation failed: %s.", SDL_GetError()); if (Mix_OpenAudio(digi_sample_rate, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, SOUND_BUFFER_SIZE)) { //edited on 10/05/98 by Matt Mueller - should keep running, just with no sound. con_printf(CON_URGENT,"\nError: Couldn't open audio: %s\n", SDL_GetError()); GameArg.SndNoSound = 1; return 1; } digi_max_channels = Mix_AllocateChannels(digi_max_channels); memset(channels, 0, MAX_SOUND_SLOTS); Mix_Pause(0); digi_initialised = 1; digi_mixer_set_digi_volume( (GameCfg.DigiVolume*32768)/8 ); return 0; } /* Shut down audio */ void digi_mixer_close() { if (MIX_DIGI_DEBUG) con_printf(CON_DEBUG,"digi_close (SDL_Mixer)\n"); if (!digi_initialised) return; digi_initialised = 0; Mix_CloseAudio(); } /* channel management */ int digi_mixer_find_channel() { int i; for (i = 0; i < digi_max_channels; i++) if (channels[i] == 0) return i; return -1; } void digi_mixer_free_channel(int channel_num) { channels[channel_num] = 0; } /* * Play-time conversion. Performs output conversion only once per sound effect used. * Once the sound sample has been converted, it is cached in SoundChunks[] */ void mixdigi_convert_sound(int i) { SDL_AudioCVT cvt; Uint8 *data = GameSounds[i].data; Uint32 dlen = GameSounds[i].length; int freq = GameSounds[i].freq; //int bits = GameSounds[i].bits; if (SoundChunks[i].abuf) return; //proceed only if not converted yet if (data) { if (MIX_DIGI_DEBUG) con_printf(CON_DEBUG,"converting %d (%d)\n", i, dlen); SDL_BuildAudioCVT(&cvt, AUDIO_U8, 1, freq, MIX_OUTPUT_FORMAT, MIX_OUTPUT_CHANNELS, digi_sample_rate); cvt.buf = malloc(dlen * cvt.len_mult); cvt.len = dlen; memcpy(cvt.buf, data, dlen); if (SDL_ConvertAudio(&cvt)) con_printf(CON_DEBUG,"conversion of %d failed\n", i); SoundChunks[i].abuf = cvt.buf; SoundChunks[i].alen = dlen * cvt.len_mult; SoundChunks[i].allocated = 1; SoundChunks[i].volume = 128; // Max volume = 128 } } // Volume 0-F1_0 int digi_mixer_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj) { int mix_vol = fix2byte(fixmul(digi_volume, volume)); int mix_pan = fix2byte(pan); int mix_loop = looping * -1; int channel; if (!digi_initialised) return -1; Assert(GameSounds[soundnum].data != (void *)-1); mixdigi_convert_sound(soundnum); if (MIX_DIGI_DEBUG) con_printf(CON_DEBUG,"digi_start_sound %d, volume %d, pan %d (start=%d, end=%d)\n", soundnum, mix_vol, mix_pan, loop_start, loop_end); channel = digi_mixer_find_channel(); Mix_PlayChannel(channel, &(SoundChunks[soundnum]), mix_loop); Mix_SetPanning(channel, 255-mix_pan, mix_pan); if (volume > F1_0) Mix_SetDistance(channel, 0); else Mix_SetDistance(channel, 255-mix_vol); channels[channel] = 1; Mix_ChannelFinished(digi_mixer_free_channel); return channel; } void digi_mixer_set_channel_volume(int channel, int volume) { int mix_vol = fix2byte(volume); if (!digi_initialised) return; Mix_SetDistance(channel, 255-mix_vol); } void digi_mixer_set_channel_pan(int channel, int pan) { int mix_pan = fix2byte(pan); Mix_SetPanning(channel, 255-mix_pan, mix_pan); } void digi_mixer_stop_sound(int channel) { if (!digi_initialised) return; if (MIX_DIGI_DEBUG) con_printf(CON_DEBUG,"digi_stop_sound %d\n", channel); Mix_HaltChannel(channel); channels[channel] = 0; } void digi_mixer_end_sound(int channel) { digi_mixer_stop_sound(channel); channels[channel] = 0; } void digi_mixer_set_digi_volume( int dvolume ) { digi_volume = dvolume; if (!digi_initialised) return; Mix_Volume(-1, fix2byte(dvolume)); } int digi_mixer_is_sound_playing(int soundno) { return 0; } int digi_mixer_is_channel_playing(int channel) { return 0; } void digi_mixer_reset() {} void digi_mixer_stop_all_channels() { Mix_HaltChannel(-1); memset(channels, 0, MAX_SOUND_SLOTS); } extern void digi_end_soundobj(int channel); //added on 980905 by adb to make sound channel setting work void digi_mixer_set_max_channels(int n) { } int digi_mixer_get_max_channels() { return digi_max_channels; } // end edit by adb #ifndef NDEBUG void digi_mixer_debug() {} #endif dxx-rebirth-0.58.1-d1x/arch/sdl/digi_mixer_music.c000066400000000000000000000073531217717257200217450ustar00rootroot00000000000000/* * This is an alternate backend for the music system. * It uses SDL_mixer to provide a more reliable playback, * and allow processing of multiple audio formats. * * -- MD2211 (2006-04-24) */ #include #if !(defined(__APPLE__) && defined(__MACH__)) #include #else #include #endif #include #include #include "args.h" #include "hmp.h" #include "digi_mixer_music.h" #include "u_mem.h" #include "console.h" #ifdef _WIN32 extern int digi_win32_play_midi_song( char * filename, int loop ); #endif Mix_Music *current_music = NULL; static unsigned char *current_music_hndlbuf = NULL; /* * Plays a music file from an absolute path or a relative path */ int mix_play_file(char *filename, int loop, void (*hook_finished_track)()) { SDL_RWops *rw = NULL; PHYSFS_file *filehandle = NULL; char full_path[PATH_MAX]; char *fptr; unsigned int bufsize = 0; mix_free_music(); // stop and free what we're already playing, if anything fptr = strrchr(filename, '.'); if (fptr == NULL) return 0; // It's a .hmp! if (!d_stricmp(fptr, ".hmp")) { hmp2mid(filename, ¤t_music_hndlbuf, &bufsize); rw = SDL_RWFromConstMem(current_music_hndlbuf,bufsize*sizeof(char)); current_music = Mix_LoadMUS_RW(rw); } // try loading music via given filename if (!current_music) current_music = Mix_LoadMUS(filename); // allow the shell convention tilde character to mean the user's home folder // chiefly used for default jukebox level song music referenced in 'descent.m3u' for Mac OS X if (!current_music && *filename == '~') { snprintf(full_path, PATH_MAX, "%s%s", PHYSFS_getUserDir(), &filename[1 + (!strncmp(&filename[1], PHYSFS_getDirSeparator(), strlen(PHYSFS_getDirSeparator())) ? strlen(PHYSFS_getDirSeparator()) : 0)]); current_music = Mix_LoadMUS(full_path); if (current_music) filename = full_path; // used later for possible error reporting } // no luck. so it might be in Searchpath. So try to build absolute path if (!current_music) { PHYSFSX_getRealPath(filename, full_path); current_music = Mix_LoadMUS(full_path); if (current_music) filename = full_path; // used later for possible error reporting } // still nothin'? Let's open via PhysFS in case it's located inside an archive if (!current_music) { filehandle = PHYSFS_openRead(filename); if (filehandle != NULL) { current_music_hndlbuf = d_realloc(current_music_hndlbuf, sizeof(char *)*PHYSFS_fileLength(filehandle)); bufsize = PHYSFS_read(filehandle, current_music_hndlbuf, sizeof(char), PHYSFS_fileLength(filehandle)); rw = SDL_RWFromConstMem(current_music_hndlbuf,bufsize*sizeof(char)); PHYSFS_close(filehandle); current_music = Mix_LoadMUS_RW(rw); } } if (current_music) { Mix_PlayMusic(current_music, (loop ? -1 : 1)); Mix_HookMusicFinished(hook_finished_track ? hook_finished_track : mix_free_music); return 1; } else { con_printf(CON_CRITICAL,"Music %s could not be loaded: %s\n", filename, Mix_GetError()); mix_stop_music(); } return 0; } // What to do when stopping song playback void mix_free_music() { Mix_HaltMusic(); if (current_music) { Mix_FreeMusic(current_music); current_music = NULL; } if (current_music_hndlbuf) { d_free(current_music_hndlbuf); current_music_hndlbuf = NULL; } } void mix_set_music_volume(int vol) { vol *= MIX_MAX_VOLUME/8; Mix_VolumeMusic(vol); } void mix_stop_music() { Mix_HaltMusic(); if (current_music_hndlbuf) { d_free(current_music_hndlbuf); current_music_hndlbuf = NULL; } } void mix_pause_music() { Mix_PauseMusic(); } void mix_resume_music() { Mix_ResumeMusic(); } void mix_pause_resume_music() { if (Mix_PausedMusic()) Mix_ResumeMusic(); else if (Mix_PlayingMusic()) Mix_PauseMusic(); } dxx-rebirth-0.58.1-d1x/arch/sdl/event.c000066400000000000000000000105061217717257200175400ustar00rootroot00000000000000/* * * SDL Event related stuff * * */ #include #include #include "event.h" #include "key.h" #include "mouse.h" #include "window.h" #include "timer.h" #include "config.h" #include "joy.h" extern void key_handler(SDL_KeyboardEvent *event); extern void mouse_button_handler(SDL_MouseButtonEvent *mbe); extern void mouse_motion_handler(SDL_MouseMotionEvent *mme); extern void mouse_cursor_autohide(); static int initialised=0; void event_poll() { SDL_Event event; int clean_uniframe=1; window *wind = window_get_front(); int idle = 1; // If the front window changes, exit this loop, otherwise unintended behavior can occur // like pressing 'Return' really fast at 'Difficulty Level' causing multiple games to be started while ((wind == window_get_front()) && SDL_PollEvent(&event)) { switch(event.type) { case SDL_KEYDOWN: case SDL_KEYUP: if (clean_uniframe) memset(unicode_frame_buffer,'\0',sizeof(unsigned char)*KEY_BUFFER_SIZE); clean_uniframe=0; key_handler((SDL_KeyboardEvent *)&event); idle = 0; break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: mouse_button_handler((SDL_MouseButtonEvent *)&event); idle = 0; break; case SDL_MOUSEMOTION: mouse_motion_handler((SDL_MouseMotionEvent *)&event); idle = 0; break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: joy_button_handler((SDL_JoyButtonEvent *)&event); idle = 0; break; case SDL_JOYAXISMOTION: if (joy_axis_handler((SDL_JoyAxisEvent *)&event)) idle = 0; break; case SDL_JOYHATMOTION: joy_hat_handler((SDL_JoyHatEvent *)&event); idle = 0; break; case SDL_JOYBALLMOTION: break; case SDL_QUIT: { d_event qevent = { EVENT_QUIT }; call_default_handler(&qevent); idle = 0; } break; } } // Send the idle event if there were no other events if (idle) { d_event ievent; ievent.type = EVENT_IDLE; event_send(&ievent); } else event_reset_idle_seconds(); mouse_cursor_autohide(); } void event_flush() { SDL_Event event; while (SDL_PollEvent(&event)); } int event_init() { // We should now be active and responding to events. initialised = 1; return 0; } int (*default_handler)(d_event *event) = NULL; void set_default_handler(int (*handler)(d_event *event)) { default_handler = handler; } int call_default_handler(d_event *event) { if (default_handler) return (*default_handler)(event); return 0; } void event_send(d_event *event) { window *wind; int handled = 0; for (wind = window_get_front(); wind != NULL && !handled; wind = window_get_prev(wind)) if (window_is_visible(wind)) { handled = window_send_event(wind, event); if (!window_exists(wind)) // break away if necessary: window_send_event() could have closed wind by now break; if (window_is_modal(wind)) break; } if (!handled) call_default_handler(event); } // Process the first event in queue, sending to the appropriate handler // This is the new object-oriented system // Uses the old system for now, but this may change void event_process(void) { d_event event; window *wind = window_get_front(); timer_update(); event_poll(); // send input events first // Doing this prevents problems when a draw event can create a newmenu, // such as some network menus when they report a problem if (window_get_front() != wind) return; event.type = EVENT_WINDOW_DRAW; // then draw all visible windows wind = window_get_first(); while (wind != NULL) { window *prev = window_get_prev(wind); if (window_is_visible(wind)) window_send_event(wind, &event); if (!window_exists(wind)) { if (!prev) // well there isn't a previous window ... break; // ... just bail out - we've done everything for this frame we can. wind = window_get_next(prev); // the current window seemed to be closed. so take the next one from the previous which should be able to point to the one after the current closed } else wind = window_get_next(wind); } gr_flip(); } void event_toggle_focus(int activate_focus) { if (activate_focus && GameCfg.Grabinput) SDL_WM_GrabInput(SDL_GRAB_ON); else SDL_WM_GrabInput(SDL_GRAB_OFF); mouse_toggle_cursor(!activate_focus); } static fix64 last_event = 0; void event_reset_idle_seconds() { last_event = timer_query(); } fix event_get_idle_seconds() { return (timer_query() - last_event)/F1_0; } dxx-rebirth-0.58.1-d1x/arch/sdl/gr.c000066400000000000000000000156511217717257200170350ustar00rootroot00000000000000/* * * SDL video functions. * */ #include #include #include #include #include #include "gr.h" #include "grdef.h" #include "palette.h" #include "u_mem.h" #include "dxxerror.h" #include "vers_id.h" #include "gamefont.h" #include "args.h" #include "config.h" int sdl_video_flags = SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; SDL_Surface *screen,*canvas; int gr_installed = 0; void gr_flip() { SDL_Rect src, dest; dest.x = src.x = dest.y = src.y = 0; dest.w = src.w = canvas->w; dest.h = src.h = canvas->h; SDL_BlitSurface(canvas, &src, screen, &dest); SDL_Flip(screen); } // Set the buffer to draw to. 0 is front, 1 is back // With SDL, can't use it without resetting the video mode void gr_set_draw_buffer(int buf) { buf = buf; } // returns possible (fullscreen) resolutions if any. int gr_list_modes( u_int32_t gsmodes[] ) { SDL_Rect** modes; int i = 0, modesnum = 0; int sdl_check_flags = sdl_video_flags; sdl_check_flags |= SDL_FULLSCREEN; // always use Fullscreen as lead. modes = SDL_ListModes(NULL, sdl_check_flags); if (modes == (SDL_Rect**)0) // check if we get any modes - if not, return 0 return 0; if (modes == (SDL_Rect**)-1) { return 0; // can obviously use any resolution... strange! } else { for (i = 0; modes[i]; ++i) { if (modes[i]->w > 0xFFF0 || modes[i]->h > 0xFFF0 // resolutions saved in 32bits. so skip bigger ones (unrealistic in 2010) (kreatordxx - made 0xFFF0 to kill warning) || modes[i]->w < 320 || modes[i]->h < 200) // also skip everything smaller than 320x200 continue; gsmodes[modesnum] = SM(modes[i]->w,modes[i]->h); modesnum++; if (modesnum >= 50) // that really seems to be enough big boy. break; } return modesnum; } } int gr_check_mode(u_int32_t mode) { unsigned int w, h; w=SM_W(mode); h=SM_H(mode); return SDL_VideoModeOK(w,h,GameArg.DbgBpp,sdl_video_flags); } int gr_set_mode(u_int32_t mode) { unsigned int w, h; if (mode<=0) return 0; w=SM_W(mode); h=SM_H(mode); screen=NULL; SDL_WM_SetCaption(DESCENT_VERSION, "Descent"); SDL_WM_SetIcon( SDL_LoadBMP( "d1x-rebirth.bmp" ), NULL ); if(SDL_VideoModeOK(w,h,GameArg.DbgBpp,sdl_video_flags)) { screen=SDL_SetVideoMode(w, h, GameArg.DbgBpp, sdl_video_flags); } else { con_printf(CON_URGENT,"Cannot set %ix%i. Fallback to 640x480\n",w,h); w=640; h=480; Game_screen_mode=mode=SM(w,h); screen=SDL_SetVideoMode(w, h, GameArg.DbgBpp, sdl_video_flags); } if (screen == NULL) { Error("Could not set %dx%dx%d video mode\n",w,h,GameArg.DbgBpp); exit(1); } canvas = SDL_CreateRGBSurface(sdl_video_flags, w, h, 8, 0, 0, 0, 0); if (canvas == NULL) { Error("Could not create canvas surface\n"); exit(1); } memset(grd_curscreen, 0, sizeof(grs_screen)); grd_curscreen->sc_mode = mode; grd_curscreen->sc_w = w; grd_curscreen->sc_h = h; grd_curscreen->sc_aspect = fixdiv(grd_curscreen->sc_w*GameCfg.AspectX,grd_curscreen->sc_h*GameCfg.AspectY); gr_init_canvas(&grd_curscreen->sc_canvas, canvas->pixels, BM_LINEAR, w, h); window_update_canvases(); gr_set_current_canvas(NULL); SDL_ShowCursor(0); gamefont_choose_game_font(w,h); gr_palette_load(gr_palette); return 0; } int gr_check_fullscreen(void) { return (sdl_video_flags & SDL_FULLSCREEN)?1:0; } int gr_toggle_fullscreen(void) { sdl_video_flags^=SDL_FULLSCREEN; SDL_WM_ToggleFullScreen(screen); GameCfg.WindowMode = (sdl_video_flags & SDL_FULLSCREEN)?0:1; return (sdl_video_flags & SDL_FULLSCREEN)?1:0; } void gr_set_attributes(void) { } int gr_init(int mode) { int retcode; // Only do this function once! if (gr_installed==1) return -1; if (SDL_Init(SDL_INIT_VIDEO) < 0) { Error("SDL library video initialisation failed: %s.",SDL_GetError()); } MALLOC( grd_curscreen,grs_screen,1 ); memset( grd_curscreen, 0, sizeof(grs_screen)); if (!GameCfg.WindowMode && !GameArg.SysWindow) sdl_video_flags|=SDL_FULLSCREEN; if (GameArg.SysNoBorders) sdl_video_flags|=SDL_NOFRAME; if (GameArg.DbgSdlHWSurface) sdl_video_flags|=SDL_HWSURFACE; if (GameArg.DbgSdlASyncBlit) sdl_video_flags|=SDL_ASYNCBLIT; // Set the mode. if ((retcode=gr_set_mode(mode))) return retcode; grd_curscreen->sc_canvas.cv_color = 0; grd_curscreen->sc_canvas.cv_fade_level = GR_FADE_OFF; grd_curscreen->sc_canvas.cv_blend_func = GR_BLEND_NORMAL; grd_curscreen->sc_canvas.cv_drawmode = 0; grd_curscreen->sc_canvas.cv_font = NULL; grd_curscreen->sc_canvas.cv_font_fg_color = 0; grd_curscreen->sc_canvas.cv_font_bg_color = 0; gr_set_current_canvas( &grd_curscreen->sc_canvas ); gr_installed = 1; return 0; } void gr_close() { if (gr_installed==1) { gr_installed = 0; d_free(grd_curscreen); SDL_ShowCursor(1); SDL_FreeSurface(canvas); } } // Palette functions follow. static int last_r=0, last_g=0, last_b=0; void gr_palette_step_up( int r, int g, int b ) { int i; ubyte *p = gr_palette; int temp; SDL_Palette *palette; SDL_Color colors[256]; if ( (r==last_r) && (g==last_g) && (b==last_b) ) return; last_r = r; last_g = g; last_b = b; palette = canvas->format->palette; if (palette == NULL) return; // Display is not palettised for (i=0; i<256; i++) { temp = (int)(*p++) + r + gr_palette_gamma; if (temp<0) temp=0; else if (temp>63) temp=63; colors[i].r = temp * 4; temp = (int)(*p++) + g + gr_palette_gamma; if (temp<0) temp=0; else if (temp>63) temp=63; colors[i].g = temp * 4; temp = (int)(*p++) + b + gr_palette_gamma; if (temp<0) temp=0; else if (temp>63) temp=63; colors[i].b = temp * 4; } SDL_SetColors(canvas, colors, 0, 256); } #undef min static inline int min(int x, int y) { return x < y ? x : y; } void gr_palette_load( ubyte *pal ) { int i, j; SDL_Palette *palette; SDL_Color colors[256]; ubyte gamma[64]; if (memcmp(pal,gr_current_pal,768)) SDL_FillRect(canvas, NULL, SDL_MapRGB(canvas->format, 0, 0, 0)); for (i=0; i<768; i++ ) { gr_current_pal[i] = pal[i]; if (gr_current_pal[i] > 63) gr_current_pal[i] = 63; } if (canvas == NULL) return; palette = canvas->format->palette; if (palette == NULL) return; // Display is not palettised for (i=0;i<64;i++) gamma[i] = (int)((pow(((double)(14)/(double)(32)), 1.0)*i) + 0.5); for (i = 0, j = 0; j < 256; j++) { int c; c = gr_find_closest_color(gamma[gr_palette[j*3]],gamma[gr_palette[j*3+1]],gamma[gr_palette[j*3+2]]); gr_fade_table[14*256+j] = c; colors[j].r = (min(gr_current_pal[i++] + gr_palette_gamma, 63)) * 4; colors[j].g = (min(gr_current_pal[i++] + gr_palette_gamma, 63)) * 4; colors[j].b = (min(gr_current_pal[i++] + gr_palette_gamma, 63)) * 4; } SDL_SetColors(canvas, colors, 0, 256); init_computed_colors(); } void gr_palette_read(ubyte * pal) { SDL_Palette *palette; int i, j; palette = canvas->format->palette; if (palette == NULL) return; // Display is not palettised for (i = 0, j=0; i < 256; i++) { pal[j++] = palette->colors[i].r / 4; pal[j++] = palette->colors[i].g / 4; pal[j++] = palette->colors[i].b / 4; } } dxx-rebirth-0.58.1-d1x/arch/sdl/init.c000066400000000000000000000016061217717257200173630ustar00rootroot00000000000000// Holds the main init and de-init functions for arch-related program parts #include #include "songs.h" #include "key.h" #include "digi.h" #include "mouse.h" #include "joy.h" #include "gr.h" #include "dxxerror.h" #include "text.h" #include "args.h" #include "config.h" void arch_close(void) { songs_uninit(); gr_close(); if (!GameArg.CtlNoJoystick) joy_close(); mouse_close(); if (!GameArg.SndNoSound) { digi_close(); } key_close(); SDL_Quit(); } void arch_init(void) { int t; if (SDL_Init(SDL_INIT_VIDEO) < 0) Error("SDL library initialisation failed: %s.",SDL_GetError()); key_init(); digi_select_system( GameArg.SndDisableSdlMixer ? SDLAUDIO_SYSTEM : SDLMIXER_SYSTEM ); if (!GameArg.SndNoSound) digi_init(); mouse_init(); if (!GameArg.CtlNoJoystick) joy_init(); if ((t = gr_init(0)) != 0) Error(TXT_CANT_INIT_GFX,t); atexit(arch_close); } dxx-rebirth-0.58.1-d1x/arch/sdl/joy.c000066400000000000000000000203111217717257200172130ustar00rootroot00000000000000/* * * SDL joystick support * */ #include // for memset #include "joy.h" #include "dxxerror.h" #include "timer.h" #include "console.h" #include "event.h" #include "text.h" #include "u_mem.h" #include "playsave.h" extern char *joybutton_text[]; //from kconfig.c extern char *joyaxis_text[]; //from kconfig.c int num_joysticks = 0; int joy_num_axes = 0; /* This struct is a "virtual" joystick, which includes all the axes * and buttons of every joystick found. */ static struct joyinfo { int n_axes; int n_buttons; int axis_value[JOY_MAX_AXES]; ubyte button_state[JOY_MAX_BUTTONS]; ubyte button_last_state[JOY_MAX_BUTTONS]; // for HAT movement only } Joystick; typedef struct d_event_joystickbutton { event_type type; int button; } d_event_joystickbutton; typedef struct d_event_joystick_moved { event_type type; // EVENT_JOYSTICK_MOVED int axis; int value; } d_event_joystick_moved; /* This struct is an array, with one entry for each physical joystick * found. */ static struct { SDL_Joystick *handle; int n_axes; int n_buttons; int n_hats; int hat_map[MAX_HATS_PER_JOYSTICK]; //Note: Descent expects hats to be buttons, so these are indices into Joystick.buttons int axis_map[MAX_AXES_PER_JOYSTICK]; int button_map[MAX_BUTTONS_PER_JOYSTICK]; } SDL_Joysticks[MAX_JOYSTICKS]; void joy_button_handler(SDL_JoyButtonEvent *jbe) { int button; d_event_joystickbutton event; button = SDL_Joysticks[jbe->which].button_map[jbe->button]; Joystick.button_state[button] = jbe->state; event.type = (jbe->type == SDL_JOYBUTTONDOWN) ? EVENT_JOYSTICK_BUTTON_DOWN : EVENT_JOYSTICK_BUTTON_UP; event.button = button; con_printf(CON_DEBUG, "Sending event %s, button %d\n", (jbe->type == SDL_JOYBUTTONDOWN) ? "EVENT_JOYSTICK_BUTTON_DOWN" : "EVENT_JOYSTICK_JOYSTICK_UP", event.button); event_send((d_event *)&event); } void joy_hat_handler(SDL_JoyHatEvent *jhe) { int hat = SDL_Joysticks[jhe->which].hat_map[jhe->hat]; int hbi; d_event_joystickbutton event; //Save last state of the hat-button Joystick.button_last_state[hat ] = Joystick.button_state[hat ]; Joystick.button_last_state[hat+1] = Joystick.button_state[hat+1]; Joystick.button_last_state[hat+2] = Joystick.button_state[hat+2]; Joystick.button_last_state[hat+3] = Joystick.button_state[hat+3]; //get current state of the hat-button Joystick.button_state[hat ] = ((jhe->value & SDL_HAT_UP)>0); Joystick.button_state[hat+1] = ((jhe->value & SDL_HAT_RIGHT)>0); Joystick.button_state[hat+2] = ((jhe->value & SDL_HAT_DOWN)>0); Joystick.button_state[hat+3] = ((jhe->value & SDL_HAT_LEFT)>0); //determine if a hat-button up or down event based on state and last_state for(hbi=0;hbi<4;hbi++) { if( !Joystick.button_last_state[hat+hbi] && Joystick.button_state[hat+hbi]) //last_state up, current state down { event.type = EVENT_JOYSTICK_BUTTON_DOWN; event.button = hat+hbi; con_printf(CON_DEBUG, "Sending event EVENT_JOYSTICK_BUTTON_DOWN, button %d\n", event.button); event_send((d_event *)&event); } else if(Joystick.button_last_state[hat+hbi] && !Joystick.button_state[hat+hbi]) //last_state down, current state up { event.type = EVENT_JOYSTICK_BUTTON_UP; event.button = hat+hbi; con_printf(CON_DEBUG, "Sending event EVENT_JOYSTICK_BUTTON_UP, button %d\n", event.button); event_send((d_event *)&event); } } } int joy_axis_handler(SDL_JoyAxisEvent *jae) { int axis; d_event_joystick_moved event; axis = SDL_Joysticks[jae->which].axis_map[jae->axis]; // inaccurate stick is inaccurate. SDL might send SDL_JoyAxisEvent even if the value is the same as before. if (Joystick.axis_value[axis] == jae->value/256) return 0; event.type = EVENT_JOYSTICK_MOVED; event.axis = axis; event.value = Joystick.axis_value[axis] = jae->value/256; con_printf(CON_DEBUG, "Sending event EVENT_JOYSTICK_MOVED, axis: %d, value: %d\n",event.axis, event.value); event_send((d_event *)&event); return 1; } /* ----------------------------------------------- */ void joy_init() { int i,j,n; char temp[10]; if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { con_printf(CON_NORMAL, "sdl-joystick: initialisation failed: %s.",SDL_GetError()); return; } memset(&Joystick,0,sizeof(Joystick)); memset(joyaxis_text, 0, JOY_MAX_AXES * sizeof(char *)); memset(joybutton_text, 0, JOY_MAX_BUTTONS * sizeof(char *)); n = SDL_NumJoysticks(); con_printf(CON_NORMAL, "sdl-joystick: found %d joysticks\n", n); for (i = 0; i < n; i++) { con_printf(CON_NORMAL, "sdl-joystick %d: %s\n", i, SDL_JoystickName(i)); SDL_Joysticks[num_joysticks].handle = SDL_JoystickOpen(i); if (SDL_Joysticks[num_joysticks].handle) { SDL_Joysticks[num_joysticks].n_axes = SDL_JoystickNumAxes(SDL_Joysticks[num_joysticks].handle); if(SDL_Joysticks[num_joysticks].n_axes > MAX_AXES_PER_JOYSTICK) { Warning("sdl-joystick: found %d axes, only %d supported.\n", SDL_Joysticks[num_joysticks].n_axes, MAX_AXES_PER_JOYSTICK); Warning("sdl-joystick: found %d axes, only %d supported.\n", SDL_Joysticks[num_joysticks].n_axes, MAX_AXES_PER_JOYSTICK); SDL_Joysticks[num_joysticks].n_axes = MAX_AXES_PER_JOYSTICK; } SDL_Joysticks[num_joysticks].n_buttons = SDL_JoystickNumButtons(SDL_Joysticks[num_joysticks].handle); if(SDL_Joysticks[num_joysticks].n_buttons > MAX_BUTTONS_PER_JOYSTICK) { Warning("sdl-joystick: found %d buttons, only %d supported.\n", SDL_Joysticks[num_joysticks].n_buttons, MAX_BUTTONS_PER_JOYSTICK); SDL_Joysticks[num_joysticks].n_buttons = MAX_BUTTONS_PER_JOYSTICK; } SDL_Joysticks[num_joysticks].n_hats = SDL_JoystickNumHats(SDL_Joysticks[num_joysticks].handle); if(SDL_Joysticks[num_joysticks].n_hats > MAX_HATS_PER_JOYSTICK) { Warning("sdl-joystick: found %d hats, only %d supported.\n", SDL_Joysticks[num_joysticks].n_hats, MAX_HATS_PER_JOYSTICK); SDL_Joysticks[num_joysticks].n_hats = MAX_HATS_PER_JOYSTICK; } con_printf(CON_NORMAL, "sdl-joystick: %d axes\n", SDL_Joysticks[num_joysticks].n_axes); con_printf(CON_NORMAL, "sdl-joystick: %d buttons\n", SDL_Joysticks[num_joysticks].n_buttons); con_printf(CON_NORMAL, "sdl-joystick: %d hats\n", SDL_Joysticks[num_joysticks].n_hats); for (j=0; j < SDL_Joysticks[num_joysticks].n_axes; j++) { sprintf(temp, "J%d A%d", i + 1, j + 1); joyaxis_text[Joystick.n_axes] = d_strdup(temp); SDL_Joysticks[num_joysticks].axis_map[j] = Joystick.n_axes++; } for (j=0; j < SDL_Joysticks[num_joysticks].n_buttons; j++) { sprintf(temp, "J%d B%d", i + 1, j + 1); joybutton_text[Joystick.n_buttons] = d_strdup(temp); SDL_Joysticks[num_joysticks].button_map[j] = Joystick.n_buttons++; } for (j=0; j < SDL_Joysticks[num_joysticks].n_hats; j++) { SDL_Joysticks[num_joysticks].hat_map[j] = Joystick.n_buttons; //a hat counts as four buttons sprintf(temp, "J%d H%d%c", i + 1, j + 1, 0202); joybutton_text[Joystick.n_buttons++] = d_strdup(temp); sprintf(temp, "J%d H%d%c", i + 1, j + 1, 0177); joybutton_text[Joystick.n_buttons++] = d_strdup(temp); sprintf(temp, "J%d H%d%c", i + 1, j + 1, 0200); joybutton_text[Joystick.n_buttons++] = d_strdup(temp); sprintf(temp, "J%d H%d%c", i + 1, j + 1, 0201); joybutton_text[Joystick.n_buttons++] = d_strdup(temp); } num_joysticks++; } else con_printf(CON_NORMAL, "sdl-joystick: initialization failed!\n"); con_printf(CON_NORMAL, "sdl-joystick: %d axes (total)\n", Joystick.n_axes); con_printf(CON_NORMAL, "sdl-joystick: %d buttons (total)\n", Joystick.n_buttons); } joy_num_axes = Joystick.n_axes; } void joy_close() { SDL_JoystickClose(SDL_Joysticks[num_joysticks].handle); while (Joystick.n_axes--) d_free(joyaxis_text[Joystick.n_axes]); while (Joystick.n_buttons--) d_free(joybutton_text[Joystick.n_buttons]); } void event_joystick_get_axis(d_event *event, int *axis, int *value) { Assert(event->type == EVENT_JOYSTICK_MOVED); *axis = ((d_event_joystick_moved *)event)->axis; *value = ((d_event_joystick_moved *)event)->value; } void joy_flush() { int i; if (!num_joysticks) return; for (i = 0; i < Joystick.n_buttons; i++) Joystick.button_state[i] = SDL_RELEASED; } int event_joystick_get_button(d_event *event) { Assert((event->type == EVENT_JOYSTICK_BUTTON_DOWN) || (event->type == EVENT_JOYSTICK_BUTTON_UP)); return ((d_event_joystickbutton *)event)->button; } dxx-rebirth-0.58.1-d1x/arch/sdl/jukebox.c000066400000000000000000000202021217717257200200600ustar00rootroot00000000000000/* * DXX Rebirth "jukebox" code * MD 2211 , 2007 */ #include #include #include #include "physfsx.h" #include "args.h" #include "dl_list.h" #include "hudmsg.h" #include "songs.h" #include "jukebox.h" #include "dxxerror.h" #include "console.h" #include "config.h" #define MUSIC_HUDMSG_MAXLEN 40 #define JUKEBOX_HUDMSG_PLAYING "Now playing:" #define JUKEBOX_HUDMSG_STOPPED "Jukebox stopped" typedef struct jukebox_songs { char **list; // the actual list char *list_buf; // buffer containing song file path text int num_songs; // number of jukebox songs int max_songs; // maximum number of pointers that 'list' can hold, i.e. size of list / size of one pointer int max_buf; // size of list_buf } jukebox_songs; static jukebox_songs JukeboxSongs = { NULL, NULL, 0, 0, 0 }; char hud_msg_buf[MUSIC_HUDMSG_MAXLEN+4]; void jukebox_unload() { if (JukeboxSongs.list_buf) { d_free(JukeboxSongs.list_buf); if (JukeboxSongs.list) d_free(JukeboxSongs.list); } else if (JukeboxSongs.list) { PHYSFS_freeList(JukeboxSongs.list); JukeboxSongs.list = NULL; } JukeboxSongs.num_songs = JukeboxSongs.max_songs = JukeboxSongs.max_buf = 0; } const char *const jukebox_exts[] = { SONG_EXT_HMP, SONG_EXT_MID, SONG_EXT_OGG, SONG_EXT_FLAC, SONG_EXT_MP3, NULL }; int read_m3u(void) { FILE *fp; int length; char *buf; char *abspath; MALLOC(abspath, char, PATH_MAX); if (!abspath) return 0; if (PHYSFSX_exists(GameCfg.CMLevelMusicPath,0)) // it's a child of Sharepath, build full path PHYSFSX_getRealPath(GameCfg.CMLevelMusicPath, abspath); else { strncpy(abspath, GameCfg.CMLevelMusicPath, PATH_MAX - 1); abspath[PATH_MAX - 1] = '\0'; } fp = fopen(abspath, "rb"); d_free(abspath); if (!fp) return 0; fseek( fp, -1, SEEK_END ); length = ftell(fp) + 1; MALLOC(JukeboxSongs.list_buf, char, length + 1); if (!JukeboxSongs.list_buf) { fclose(fp); return 0; } fseek(fp, 0, SEEK_SET); if (!fread(JukeboxSongs.list_buf, length, 1, fp)) { d_free(JukeboxSongs.list_buf); fclose(fp); return 0; } fclose(fp); // Finished with it // The growing string list is allocated last, hopefully reducing memory fragmentation when it grows MALLOC(JukeboxSongs.list, char *, 1024); if (!JukeboxSongs.list) { d_free(JukeboxSongs.list_buf); return 0; } JukeboxSongs.max_songs = 1024; JukeboxSongs.list_buf[length] = '\0'; // make sure the last string is terminated JukeboxSongs.max_buf = length + 1; buf = JukeboxSongs.list_buf; while (buf < JukeboxSongs.list_buf + length - 1) { while (*buf == 0 || *buf == 10 || *buf == 13) // find new line - support DOS, Unix and Mac line endings buf++; if (*buf != '#') // ignore comments / extra info { if (JukeboxSongs.num_songs >= JukeboxSongs.max_songs) { char **new_list = d_realloc(JukeboxSongs.list, JukeboxSongs.max_buf*sizeof(char *)*MEM_K); if (new_list == NULL) break; JukeboxSongs.max_buf *= MEM_K; JukeboxSongs.list = new_list; } JukeboxSongs.list[JukeboxSongs.num_songs++] = buf; } while (*buf != 0 && *buf != 10 && *buf != 13) // find end of line buf++; *buf = 0; } return 1; } /* Loads music file names from a given directory or M3U playlist */ void jukebox_load() { static int jukebox_init = 1; // initialize JukeboxSongs structure once per runtime if (jukebox_init) { JukeboxSongs.list = NULL; JukeboxSongs.num_songs = JukeboxSongs.max_songs = JukeboxSongs.max_buf = 0; jukebox_init = 0; } jukebox_unload(); // Check if it's an M3U file if (!d_stricmp(&GameCfg.CMLevelMusicPath[strlen(GameCfg.CMLevelMusicPath) - 4], ".m3u")) read_m3u(); else // a directory { int new_path = 0; char *p; const char *sep = PHYSFS_getDirSeparator(); int i; // stick a separator on the end if necessary. if (strlen(GameCfg.CMLevelMusicPath) >= strlen(sep)) { p = GameCfg.CMLevelMusicPath + strlen(GameCfg.CMLevelMusicPath) - strlen(sep); if (strcmp(p, sep)) strncat(GameCfg.CMLevelMusicPath, sep, PATH_MAX - 1 - strlen(GameCfg.CMLevelMusicPath)); } // Read directory using PhysicsFS if (PHYSFS_isDirectory(GameCfg.CMLevelMusicPath)) // find files in relative directory JukeboxSongs.list = PHYSFSX_findFiles(GameCfg.CMLevelMusicPath, jukebox_exts); else { new_path = PHYSFSX_isNewPath(GameCfg.CMLevelMusicPath); PHYSFS_addToSearchPath(GameCfg.CMLevelMusicPath, 0); // as mountpoints are no option (yet), make sure only files originating from GameCfg.CMLevelMusicPath are aded to the list. JukeboxSongs.list = PHYSFSX_findabsoluteFiles("", GameCfg.CMLevelMusicPath, jukebox_exts); } if (!JukeboxSongs.list) { if (new_path) PHYSFS_removeFromSearchPath(GameCfg.CMLevelMusicPath); return; } for (i = 0; JukeboxSongs.list[i]; i++) {} JukeboxSongs.num_songs = i; if (new_path) PHYSFS_removeFromSearchPath(GameCfg.CMLevelMusicPath); } if (JukeboxSongs.num_songs) { con_printf(CON_DEBUG,"Jukebox: %d music file(s) found in %s\n", JukeboxSongs.num_songs, GameCfg.CMLevelMusicPath); if (GameCfg.CMLevelMusicTrack[1] != JukeboxSongs.num_songs) { GameCfg.CMLevelMusicTrack[1] = JukeboxSongs.num_songs; GameCfg.CMLevelMusicTrack[0] = 0; // number of songs changed so start from beginning. } } else { GameCfg.CMLevelMusicTrack[0] = -1; GameCfg.CMLevelMusicTrack[1] = -1; con_printf(CON_DEBUG,"Jukebox music could not be found!\n"); } } // To proceed tru our playlist. Usually used for continous play, but can loop as well. void jukebox_hook_next() { if (!JukeboxSongs.list || GameCfg.CMLevelMusicTrack[0] == -1) return; if (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_RAND) GameCfg.CMLevelMusicTrack[0] = d_rand() % GameCfg.CMLevelMusicTrack[1]; // simply a random selection - no check if this song has already been played. But that's how I roll! else GameCfg.CMLevelMusicTrack[0]++; if (GameCfg.CMLevelMusicTrack[0] + 1 > GameCfg.CMLevelMusicTrack[1]) GameCfg.CMLevelMusicTrack[0] = 0; jukebox_play(); } // Play tracks from Jukebox directory. Play track specified in GameCfg.CMLevelMusicTrack[0] and loop depending on GameCfg.CMLevelMusicPlayOrder int jukebox_play() { char *music_filename, *full_filename; unsigned long size_full_filename = 0; if (!JukeboxSongs.list) return 0; if (GameCfg.CMLevelMusicTrack[0] < 0 || GameCfg.CMLevelMusicTrack[0] + 1 > GameCfg.CMLevelMusicTrack[1]) return 0; music_filename = JukeboxSongs.list[GameCfg.CMLevelMusicTrack[0]]; if (!music_filename) return 0; size_full_filename = strlen(GameCfg.CMLevelMusicPath)+strlen(music_filename)+1; MALLOC(full_filename, char, size_full_filename); memset(full_filename, '\0', size_full_filename); if (!d_stricmp(&GameCfg.CMLevelMusicPath[strlen(GameCfg.CMLevelMusicPath) - 4], ".m3u")) // if it's from an M3U playlist strcpy(full_filename, music_filename); else // if it's from a specified path snprintf(full_filename, size_full_filename, "%s%s", GameCfg.CMLevelMusicPath, music_filename); if (!songs_play_file(full_filename, ((GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_LEVEL)?1:0), ((GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_LEVEL)?NULL:jukebox_hook_next))) { d_free(full_filename); return 0; // whoops, got an error } // Formatting a pretty message if (strlen(music_filename) >= MUSIC_HUDMSG_MAXLEN) { strcpy(hud_msg_buf, "..."); strncat(hud_msg_buf, &music_filename[strlen(music_filename) - MUSIC_HUDMSG_MAXLEN], MUSIC_HUDMSG_MAXLEN); hud_msg_buf[MUSIC_HUDMSG_MAXLEN+3] = '\0'; } else { strcpy(hud_msg_buf, music_filename); } HUD_init_message(HM_DEFAULT, "%s %s", JUKEBOX_HUDMSG_PLAYING, hud_msg_buf); d_free(full_filename); return 1; } char *jukebox_current() { return JukeboxSongs.list[GameCfg.CMLevelMusicTrack[0]]; } int jukebox_is_loaded() { return (JukeboxSongs.list != NULL); } int jukebox_is_playing() { return GameCfg.CMLevelMusicTrack[0] + 1; } int jukebox_numtracks() { return GameCfg.CMLevelMusicTrack[1]; } void jukebox_list() { int i; if (!JukeboxSongs.list) return; if (!(*JukeboxSongs.list)) { con_printf(CON_DEBUG,"* No songs have been found\n"); } else { for (i = 0; i < GameCfg.CMLevelMusicTrack[1]; i++) con_printf(CON_DEBUG,"* %s\n", JukeboxSongs.list[i]); } } dxx-rebirth-0.58.1-d1x/arch/sdl/key.c000066400000000000000000000414531217717257200172140ustar00rootroot00000000000000/* * * SDL keyboard input support * * */ #include #include #include #include "event.h" #include "dxxerror.h" #include "key.h" #include "timer.h" #include "window.h" #include "console.h" #include "args.h" static unsigned char Installed = 0; //-------- Variable accessed by outside functions --------- int keyd_repeat = 0; // 1 = use repeats, 0 no repeats volatile unsigned char keyd_last_pressed; volatile unsigned char keyd_last_released; volatile unsigned char keyd_pressed[256]; fix64 keyd_time_when_last_pressed; unsigned char unicode_frame_buffer[KEY_BUFFER_SIZE] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; typedef struct keyboard { ubyte state[256]; } keyboard; static keyboard key_data; const key_props key_properties[256] = { { "", 255, -1 }, // 0 { "ESC", 255, SDLK_ESCAPE }, { "1", '1', SDLK_1 }, { "2", '2', SDLK_2 }, { "3", '3', SDLK_3 }, { "4", '4', SDLK_4 }, { "5", '5', SDLK_5 }, { "6", '6', SDLK_6 }, { "7", '7', SDLK_7 }, { "8", '8', SDLK_8 }, { "9", '9', SDLK_9 }, // 10 { "0", '0', SDLK_0 }, { "-", '-', SDLK_MINUS }, { "=", '=', SDLK_EQUALS }, { "BSPC", 255, SDLK_BACKSPACE }, { "TAB", 255, SDLK_TAB }, { "Q", 'q', SDLK_q }, { "W", 'w', SDLK_w }, { "E", 'e', SDLK_e }, { "R", 'r', SDLK_r }, { "T", 't', SDLK_t }, // 20 { "Y", 'y', SDLK_y }, { "U", 'u', SDLK_u }, { "I", 'i', SDLK_i }, { "O", 'o', SDLK_o }, { "P", 'p', SDLK_p }, { "[", '[', SDLK_LEFTBRACKET }, { "]", ']', SDLK_RIGHTBRACKET }, { "ENTER", 255, SDLK_RETURN }, { "LCTRL", 255, SDLK_LCTRL }, { "A", 'a', SDLK_a }, // 30 { "S", 's', SDLK_s }, { "D", 'd', SDLK_d }, { "F", 'f', SDLK_f }, { "G", 'g', SDLK_g }, { "H", 'h', SDLK_h }, { "J", 'j', SDLK_j }, { "K", 'k', SDLK_k }, { "L", 'l', SDLK_l }, { ";", ';', SDLK_SEMICOLON }, { "'", '\'', SDLK_QUOTE }, // 40 { "`", '`', SDLK_BACKQUOTE }, { "LSHFT", 255, SDLK_LSHIFT }, { "\\", '\\', SDLK_BACKSLASH }, { "Z", 'z', SDLK_z }, { "X", 'x', SDLK_x }, { "C", 'c', SDLK_c }, { "V", 'v', SDLK_v }, { "B", 'b', SDLK_b }, { "N", 'n', SDLK_n }, { "M", 'm', SDLK_m }, // 50 { ",", ',', SDLK_COMMA }, { ".", '.', SDLK_PERIOD }, { "/", '/', SDLK_SLASH }, { "RSHFT", 255, SDLK_RSHIFT }, { "PAD*", '*', SDLK_KP_MULTIPLY }, { "LALT", 255, SDLK_LALT }, { "SPC", ' ', SDLK_SPACE }, { "CPSLK", 255, SDLK_CAPSLOCK }, { "F1", 255, SDLK_F1 }, { "F2", 255, SDLK_F2 }, // 60 { "F3", 255, SDLK_F3 }, { "F4", 255, SDLK_F4 }, { "F5", 255, SDLK_F5 }, { "F6", 255, SDLK_F6 }, { "F7", 255, SDLK_F7 }, { "F8", 255, SDLK_F8 }, { "F9", 255, SDLK_F9 }, { "F10", 255, SDLK_F10 }, { "NMLCK", 255, SDLK_NUMLOCK }, { "SCLK", 255, SDLK_SCROLLOCK }, // 70 { "PAD7", 255, SDLK_KP7 }, { "PAD8", 255, SDLK_KP8 }, { "PAD9", 255, SDLK_KP9 }, { "PAD-", 255, SDLK_KP_MINUS }, { "PAD4", 255, SDLK_KP4 }, { "PAD5", 255, SDLK_KP5 }, { "PAD6", 255, SDLK_KP6 }, { "PAD+", 255, SDLK_KP_PLUS }, { "PAD1", 255, SDLK_KP1 }, { "PAD2", 255, SDLK_KP2 }, // 80 { "PAD3", 255, SDLK_KP3 }, { "PAD0", 255, SDLK_KP0 }, { "PAD.", 255, SDLK_KP_PERIOD }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "F11", 255, SDLK_F11 }, { "F12", 255, SDLK_F12 }, { "", 255, -1 }, { "", 255, -1 }, // 90 { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "PAUSE", 255, SDLK_PAUSE }, { "W0", 255, SDLK_WORLD_0 }, { "W1", 255, SDLK_WORLD_1 }, { "W2", 255, SDLK_WORLD_2 }, // 100 { "W3", 255, SDLK_WORLD_3 }, { "W4", 255, SDLK_WORLD_4 }, { "W5", 255, SDLK_WORLD_5 }, { "W6", 255, SDLK_WORLD_6 }, { "W7", 255, SDLK_WORLD_7 }, { "W8", 255, SDLK_WORLD_8 }, { "W9", 255, SDLK_WORLD_9 }, { "W10", 255, SDLK_WORLD_10 }, { "W11", 255, SDLK_WORLD_11 }, { "W12", 255, SDLK_WORLD_12 }, // 110 { "W13", 255, SDLK_WORLD_13 }, { "W14", 255, SDLK_WORLD_14 }, { "W15", 255, SDLK_WORLD_15 }, { "W16", 255, SDLK_WORLD_16 }, { "W17", 255, SDLK_WORLD_17 }, { "W18", 255, SDLK_WORLD_18 }, { "W19", 255, SDLK_WORLD_19 }, { "W20", 255, SDLK_WORLD_20 }, { "W21", 255, SDLK_WORLD_21 }, { "W22", 255, SDLK_WORLD_22 }, // 120 { "W23", 255, SDLK_WORLD_23 }, { "W24", 255, SDLK_WORLD_24 }, { "W25", 255, SDLK_WORLD_25 }, { "W26", 255, SDLK_WORLD_26 }, { "W27", 255, SDLK_WORLD_27 }, { "W28", 255, SDLK_WORLD_28 }, { "W29", 255, SDLK_WORLD_29 }, { "W30", 255, SDLK_WORLD_30 }, { "W31", 255, SDLK_WORLD_31 }, { "W32", 255, SDLK_WORLD_32 }, // 130 { "W33", 255, SDLK_WORLD_33 }, { "W34", 255, SDLK_WORLD_34 }, { "W35", 255, SDLK_WORLD_35 }, { "W36", 255, SDLK_WORLD_36 }, { "W37", 255, SDLK_WORLD_37 }, { "W38", 255, SDLK_WORLD_38 }, { "W39", 255, SDLK_WORLD_39 }, { "W40", 255, SDLK_WORLD_40 }, { "W41", 255, SDLK_WORLD_41 }, { "W42", 255, SDLK_WORLD_42 }, // 140 { "W43", 255, SDLK_WORLD_43 }, { "W44", 255, SDLK_WORLD_44 }, { "W45", 255, SDLK_WORLD_45 }, { "W46", 255, SDLK_WORLD_46 }, { "W47", 255, SDLK_WORLD_47 }, { "W48", 255, SDLK_WORLD_48 }, { "W49", 255, SDLK_WORLD_49 }, { "W50", 255, SDLK_WORLD_50 }, { "W51", 255, SDLK_WORLD_51 }, { "", 255, -1 }, // 150 { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "PAD", 255, SDLK_KP_ENTER }, { "RCTRL", 255, SDLK_RCTRL }, { "LCMD", 255, SDLK_LMETA }, { "RCMD", 255, SDLK_RMETA }, { "", 255, -1 }, // 160 { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, // 170 { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, // 180 { "PAD/", 255, SDLK_KP_DIVIDE }, { "", 255, -1 }, { "PRSCR", 255, SDLK_PRINT }, { "RALT", 255, SDLK_RALT }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, // 190 { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "", 255, -1 }, { "HOME", 255, SDLK_HOME }, { "UP", 255, SDLK_UP }, // 200 { "PGUP", 255, SDLK_PAGEUP }, { "", 255, -1 }, { "LEFT", 255, SDLK_LEFT }, { "", 255, -1 }, { "RIGHT", 255, SDLK_RIGHT }, { "", 255, -1 }, { "END", 255, SDLK_END }, { "DOWN", 255, SDLK_DOWN }, { "PGDN", 255, SDLK_PAGEDOWN }, { "INS", 255, SDLK_INSERT }, // 210 { "DEL", 255, SDLK_DELETE }, { "W52", 255, SDLK_WORLD_52 }, { "W53", 255, SDLK_WORLD_53 }, { "W54", 255, SDLK_WORLD_54 }, { "W55", 255, SDLK_WORLD_55 }, { "W56", 255, SDLK_WORLD_56 }, { "W57", 255, SDLK_WORLD_57 }, { "W58", 255, SDLK_WORLD_58 }, { "W59", 255, SDLK_WORLD_59 }, { "W60", 255, SDLK_WORLD_60 }, // 220 { "W61", 255, SDLK_WORLD_61 }, { "W62", 255, SDLK_WORLD_62 }, { "W63", 255, SDLK_WORLD_63 }, { "W64", 255, SDLK_WORLD_64 }, { "W65", 255, SDLK_WORLD_65 }, { "W66", 255, SDLK_WORLD_66 }, { "W67", 255, SDLK_WORLD_67 }, { "W68", 255, SDLK_WORLD_68 }, { "W69", 255, SDLK_WORLD_69 }, { "W70", 255, SDLK_WORLD_70 }, // 230 { "W71", 255, SDLK_WORLD_71 }, { "W72", 255, SDLK_WORLD_72 }, { "W73", 255, SDLK_WORLD_73 }, { "W74", 255, SDLK_WORLD_74 }, { "W75", 255, SDLK_WORLD_75 }, { "W76", 255, SDLK_WORLD_76 }, { "W77", 255, SDLK_WORLD_77 }, { "W78", 255, SDLK_WORLD_78 }, { "W79", 255, SDLK_WORLD_79 }, { "W80", 255, SDLK_WORLD_80 }, // 240 { "W81", 255, SDLK_WORLD_81 }, { "W82", 255, SDLK_WORLD_82 }, { "W83", 255, SDLK_WORLD_83 }, { "W84", 255, SDLK_WORLD_84 }, { "W85", 255, SDLK_WORLD_85 }, { "W86", 255, SDLK_WORLD_86 }, { "W87", 255, SDLK_WORLD_87 }, { "W88", 255, SDLK_WORLD_88 }, { "W89", 255, SDLK_WORLD_89 }, { "W90", 255, SDLK_WORLD_90 }, // 250 { "W91", 255, SDLK_WORLD_91 }, { "W92", 255, SDLK_WORLD_92 }, { "W93", 255, SDLK_WORLD_93 }, { "W94", 255, SDLK_WORLD_94 }, { "W95", 255, SDLK_WORLD_95 }, // 255 }; typedef struct d_event_keycommand { event_type type; // EVENT_KEY_COMMAND/RELEASE int keycode; } d_event_keycommand; int key_ismodlck(int keycode) { switch (keycode) { case KEY_LSHIFT: case KEY_RSHIFT: case KEY_LALT: case KEY_RALT: case KEY_LCTRL: case KEY_RCTRL: case KEY_LMETA: case KEY_RMETA: return KEY_ISMOD; case KEY_NUMLOCK: case KEY_SCROLLOCK: case KEY_CAPSLOCK: return KEY_ISLCK; default: return 0; } } unsigned char key_ascii() { static unsigned char unibuffer[KEY_BUFFER_SIZE] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; int i=0, offset=0, count=0; offset=strlen((const char*)unibuffer); // move temporal chars from unicode_frame_buffer to empty space behind last unibuffer char (if any) for (i=offset; i < KEY_BUFFER_SIZE; i++) if (unicode_frame_buffer[count] != '\0') { unibuffer[i]=unicode_frame_buffer[count]; unicode_frame_buffer[count]='\0'; count++; } // unibuffer is not empty. store first char, remove it, shift all chars one step left and then print our char if (unibuffer[0] != '\0') { unsigned char retval = unibuffer[0]; unsigned char unibuffer_shift[KEY_BUFFER_SIZE]; memset(unibuffer_shift,'\0',sizeof(unsigned char)*KEY_BUFFER_SIZE); memcpy(unibuffer_shift,unibuffer+1,sizeof(unsigned char)*(KEY_BUFFER_SIZE-1)); memcpy(unibuffer,unibuffer_shift,sizeof(unsigned char)*KEY_BUFFER_SIZE); return retval; } else return 255; } void key_handler(SDL_KeyboardEvent *kevent) { int keycode, event_keysym=-1, key_state; // Read SDLK symbol and state event_keysym = kevent->keysym.sym; key_state = (kevent->state == SDL_PRESSED)?1:0; // fill the unicode frame-related unicode buffer if (key_state && kevent->keysym.unicode > 31 && kevent->keysym.unicode < 255) { int i = 0; for (i = 0; i < KEY_BUFFER_SIZE; i++) if (unicode_frame_buffer[i] == '\0') { unicode_frame_buffer[i] = kevent->keysym.unicode; break; } } //===================================================== for (keycode = 255; keycode > 0; keycode--) if (key_properties[keycode].sym == event_keysym) break; if (keycode == 0) return; /* * process the key if: * - it's a valid key AND * - if the keystate has changed OR * - key state same as last one and game accepts key repeats but keep out mod/lock keys */ if (key_state != keyd_pressed[keycode] || (keyd_repeat && !key_ismodlck(keycode))) { d_event_keycommand event; // now update the key props if (key_state) { keyd_last_pressed = keycode; keyd_pressed[keycode] = key_data.state[keycode] = 1; } else { keyd_pressed[keycode] = key_data.state[keycode] = 0; } if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) keycode |= KEY_SHIFTED; if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT]) keycode |= KEY_ALTED; if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL]) keycode |= KEY_CTRLED; if ( keyd_pressed[KEY_DELETE] ) keycode |= KEY_DEBUGGED; if ( keyd_pressed[KEY_LMETA] || keyd_pressed[KEY_RMETA]) keycode |= KEY_METAED; // We allowed the key to be added to the queue for now, // because there are still input loops without associated windows event.type = key_state?EVENT_KEY_COMMAND:EVENT_KEY_RELEASE; event.keycode = keycode; con_printf(CON_DEBUG, "Sending event %s: %s %s %s %s %s %s\n", (key_state) ? "EVENT_KEY_COMMAND": "EVENT_KEY_RELEASE", (keycode & KEY_METAED) ? "META" : "", (keycode & KEY_DEBUGGED) ? "DEBUG" : "", (keycode & KEY_CTRLED) ? "CTRL" : "", (keycode & KEY_ALTED) ? "ALT" : "", (keycode & KEY_SHIFTED) ? "SHIFT" : "", key_properties[keycode & 0xff].key_text ); event_send((d_event *)&event); } } void key_close() { Installed = 0; } void key_init() { if (Installed) return; Installed=1; SDL_EnableUNICODE(1); key_toggle_repeat(1); keyd_time_when_last_pressed = timer_query(); // Clear the keyboard array key_flush(); } void key_flush() { int i; Uint8 *keystate = SDL_GetKeyState(NULL); if (!Installed) key_init(); //Clear the unicode buffer for (i=0; itype == EVENT_KEY_COMMAND || event->type == EVENT_KEY_RELEASE); return ((d_event_keycommand *)event)->keycode; } // same as above but without mod states int event_key_get_raw(d_event *event) { int keycode = ((d_event_keycommand *)event)->keycode; Assert(event->type == EVENT_KEY_COMMAND || event->type == EVENT_KEY_RELEASE); if ( keycode & KEY_SHIFTED ) keycode &= ~KEY_SHIFTED; if ( keycode & KEY_ALTED ) keycode &= ~KEY_ALTED; if ( keycode & KEY_CTRLED ) keycode &= ~KEY_CTRLED; if ( keycode & KEY_DEBUGGED ) keycode &= ~KEY_DEBUGGED; if ( keycode & KEY_METAED ) keycode &= ~KEY_METAED; return keycode; } void key_toggle_repeat(int enable) { if (enable) { if (SDL_EnableKeyRepeat(KEY_REPEAT_DELAY, KEY_REPEAT_INTERVAL) == 0) keyd_repeat = 1; } else { SDL_EnableKeyRepeat(0, 0); keyd_repeat = 0; } key_flush(); } dxx-rebirth-0.58.1-d1x/arch/sdl/mouse.c000066400000000000000000000140461217717257200175520ustar00rootroot00000000000000/* * * SDL mouse driver * */ #include #include #include "fix.h" #include "timer.h" #include "event.h" #include "window.h" #include "mouse.h" #include "playsave.h" #include "args.h" static struct mouseinfo { ubyte button_state[MOUSE_MAX_BUTTONS]; fix64 time_lastpressed[MOUSE_MAX_BUTTONS]; int delta_x, delta_y, delta_z, old_delta_x, old_delta_y; int x,y,z; int cursor_enabled; fix64 cursor_time; } Mouse; typedef struct d_event_mousebutton { event_type type; int button; } d_event_mousebutton; typedef struct d_event_mouse_moved { event_type type; // EVENT_MOUSE_MOVED short dx, dy, dz; } d_event_mouse_moved; void mouse_init(void) { memset(&Mouse,0,sizeof(Mouse)); } void mouse_close(void) { SDL_ShowCursor(SDL_ENABLE); } void mouse_button_handler(SDL_MouseButtonEvent *mbe) { // to bad, SDL buttons use a different mapping as descent expects, // this is at least true and tested for the first three buttons int button_remap[17] = { MBTN_LEFT, MBTN_MIDDLE, MBTN_RIGHT, MBTN_Z_UP, MBTN_Z_DOWN, MBTN_PITCH_BACKWARD, MBTN_PITCH_FORWARD, MBTN_BANK_LEFT, MBTN_BANK_RIGHT, MBTN_HEAD_LEFT, MBTN_HEAD_RIGHT, MBTN_11, MBTN_12, MBTN_13, MBTN_14, MBTN_15, MBTN_16 }; int button = button_remap[mbe->button - 1]; // -1 since SDL seems to start counting at 1 d_event_mousebutton event; if (GameArg.CtlNoMouse) return; Mouse.cursor_time = timer_query(); if (mbe->state == SDL_PRESSED) { d_event_mouse_moved event2 = { EVENT_MOUSE_MOVED, 0, 0, 0 }; Mouse.button_state[button] = 1; if (button == MBTN_Z_UP) { Mouse.delta_z += Z_SENSITIVITY; Mouse.z += Z_SENSITIVITY; event2.dz = Z_SENSITIVITY; } else if (button == MBTN_Z_DOWN) { Mouse.delta_z -= Z_SENSITIVITY; Mouse.z -= Z_SENSITIVITY; event2.dz = -1*Z_SENSITIVITY; } if (event2.dz) { //con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_MOVED, relative motion %d,%d,%d\n", // event2.dx, event2.dy, event2.dz); event_send((d_event *)&event2); } } else { Mouse.button_state[button] = 0; } event.type = (mbe->state == SDL_PRESSED) ? EVENT_MOUSE_BUTTON_DOWN : EVENT_MOUSE_BUTTON_UP; event.button = button; con_printf(CON_DEBUG, "Sending event %s, button %d, coords %d,%d,%d\n", (mbe->state == SDL_PRESSED) ? "EVENT_MOUSE_BUTTON_DOWN" : "EVENT_MOUSE_BUTTON_UP", event.button, Mouse.x, Mouse.y, Mouse.z); event_send((d_event *)&event); //Double-click support if (Mouse.button_state[button]) { if (timer_query() <= Mouse.time_lastpressed[button] + F1_0/5) { event.type = EVENT_MOUSE_DOUBLE_CLICKED; //event.button = button; // already set the button con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_DOUBLE_CLICKED, button %d, coords %d,%d\n", event.button, Mouse.x, Mouse.y); event_send((d_event *)&event); } Mouse.time_lastpressed[button] = Mouse.cursor_time; } } void mouse_motion_handler(SDL_MouseMotionEvent *mme) { d_event_mouse_moved event; if (GameArg.CtlNoMouse) return; Mouse.cursor_time = timer_query(); Mouse.x += mme->xrel; Mouse.y += mme->yrel; event.type = EVENT_MOUSE_MOVED; event.dx = mme->xrel; event.dy = mme->yrel; event.dz = 0; // handled in mouse_button_handler Mouse.old_delta_x = event.dx; Mouse.old_delta_y = event.dy; //con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_MOVED, relative motion %d,%d,%d\n", // event.dx, event.dy, event.dz); event_send((d_event *)&event); } void mouse_flush() // clears all mice events... { int i; // event_poll(); for (i=0; i= canv->cv_bitmap.bm_x) && (Mouse.x <= canv->cv_bitmap.bm_x + canv->cv_bitmap.bm_w) && (Mouse.y >= canv->cv_bitmap.bm_y) && (Mouse.y <= canv->cv_bitmap.bm_y + canv->cv_bitmap.bm_h); } void mouse_get_delta( int *dx, int *dy, int *dz ) { SDL_GetRelativeMouseState( &Mouse.delta_x, &Mouse.delta_y ); *dx = Mouse.delta_x; *dy = Mouse.delta_y; *dz = Mouse.delta_z; Mouse.old_delta_x = *dx; Mouse.old_delta_y = *dy; Mouse.delta_x = 0; Mouse.delta_y = 0; Mouse.delta_z = 0; } void event_mouse_get_delta(d_event *event, int *dx, int *dy, int *dz) { Assert(event->type == EVENT_MOUSE_MOVED); *dx = ((d_event_mouse_moved *)event)->dx; *dy = ((d_event_mouse_moved *)event)->dy; *dz = ((d_event_mouse_moved *)event)->dz; } int event_mouse_get_button(d_event *event) { Assert((event->type == EVENT_MOUSE_BUTTON_DOWN) || (event->type == EVENT_MOUSE_BUTTON_UP)); return ((d_event_mousebutton *)event)->button; } int mouse_get_btns() { int i; uint flag=1; int status = 0; // event_poll(); for (i=0; i= timer_query() && hidden_time + (F1_0/2) < timer_query() && !show) SDL_ShowCursor(SDL_ENABLE); else if ( (Mouse.cursor_time + (F1_0*2)) < timer_query() && show) { SDL_ShowCursor(SDL_DISABLE); hidden_time = timer_query(); } } else { if (show) SDL_ShowCursor(SDL_DISABLE); } } dxx-rebirth-0.58.1-d1x/arch/sdl/rbaudio.c000066400000000000000000000141051217717257200200430ustar00rootroot00000000000000/* * * SDL CD Audio functions * * */ #include #include #include #ifdef __linux__ #include #include #endif #include "pstypes.h" #include "dxxerror.h" #include "args.h" #include "rbaudio.h" #include "console.h" #include "timer.h" #define REDBOOK_VOLUME_SCALE 255 static SDL_CD *s_cd = NULL; static int initialised = 0; void RBAExit() { if (s_cd) { SDL_CDStop(s_cd); SDL_CDClose(s_cd); } } void RBAInit() { int num_cds; int i,j; if (initialised) return; if (SDL_Init(SDL_INIT_CDROM) < 0) { Warning("RBAudio: SDL library initialisation failed: %s.",SDL_GetError()); return; } num_cds = SDL_CDNumDrives(); if (num_cds < 1) { con_printf(CON_NORMAL, "RBAudio: No cdrom drives found!\n"); #if defined(__APPLE__) || defined(macintosh) SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs #endif return; } for (i = 0; i < num_cds; i++) { if (s_cd) SDL_CDClose(s_cd); s_cd = SDL_CDOpen(i); if (s_cd && CD_INDRIVE(SDL_CDStatus(s_cd))) { for (j = 0; j < s_cd->numtracks; j++) { if (s_cd->track[j].type == SDL_AUDIO_TRACK) break; } if (j != s_cd->numtracks) break; // we've found an audio CD } else if (s_cd == NULL) Warning("RBAudio: Could not open cdrom %i for redbook audio:%s\n", i, SDL_GetError()); } if (i == num_cds) { con_printf(CON_NORMAL, "RBAudio: No audio CDs found\n"); if (s_cd) // if there's no audio CD, say that there's no redbook and hence play MIDI instead { SDL_CDClose(s_cd); s_cd = NULL; } #if defined(__APPLE__) || defined(macintosh) SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs #endif return; } initialised = 1; RBAList(); } int RBAEnabled() { return initialised; } int RBAPlayTrack(int a) { if (!s_cd) return -1; if (CD_INDRIVE(SDL_CDStatus(s_cd)) ) { if (SDL_CDPlayTracks(s_cd, a-1, 0, 0, 0) == 0) { con_printf(CON_VERBOSE, "RBAudio: Playing track %i\n", a); return a; } } return -1; } void (*redbook_finished_hook)() = NULL; void RBAStop() { if (!s_cd) return; SDL_CDStop(s_cd); redbook_finished_hook = NULL; // no calling the finished hook - stopped means stopped here con_printf(CON_VERBOSE, "RBAudio: Playback stopped\n"); } void RBAEjectDisk() { if (!s_cd) return; SDL_CDEject(s_cd); // play nothing until it tries to load a song #if defined(__APPLE__) || defined(macintosh) SDL_QuitSubSystem(SDL_INIT_CDROM); // necessary for rescanning CDROMs #endif initialised = 0; } void RBASetVolume(int volume) { #ifdef __linux__ int cdfile, level; struct cdrom_volctrl volctrl; if (!s_cd) return; cdfile = s_cd->id; level = volume*REDBOOK_VOLUME_SCALE/8; if ((level<0) || (level>REDBOOK_VOLUME_SCALE)) { con_printf(CON_CRITICAL, "RBAudio: illegal volume value (allowed values 0-%i)\n",REDBOOK_VOLUME_SCALE); return; } volctrl.channel0 = volctrl.channel1 = volctrl.channel2 = volctrl.channel3 = level; if ( ioctl(cdfile, CDROMVOLCTRL, &volctrl) == -1 ) { con_printf(CON_CRITICAL, "RBAudio: CDROMVOLCTRL ioctl failed\n"); return; } #endif } void RBAPause() { if (!s_cd) return; SDL_CDPause(s_cd); con_printf(CON_VERBOSE, "RBAudio: Playback paused\n"); } int RBAResume() { if (!s_cd) return -1; SDL_CDResume(s_cd); con_printf(CON_VERBOSE, "RBAudio: Playback resumed\n"); return 1; } int RBAPauseResume() { if (!s_cd) return 0; if (SDL_CDStatus(s_cd) == CD_PLAYING) { SDL_CDPause(s_cd); con_printf(CON_VERBOSE, "RBAudio: Toggle Playback pause\n"); } else if (SDL_CDStatus(s_cd) == CD_PAUSED) { SDL_CDResume(s_cd); con_printf(CON_VERBOSE, "RBAudio: Toggle Playback resume\n"); } else return 0; return 1; } int RBAGetNumberOfTracks() { if (!s_cd) return -1; SDL_CDStatus(s_cd); con_printf(CON_VERBOSE, "RBAudio: Found %i tracks on CD\n", s_cd->numtracks); return s_cd->numtracks; } // check if we need to call the 'finished' hook // needs to go in all event loops // a real hook would be ideal, but is currently unsupported by SDL Audio CD void RBACheckFinishedHook() { static fix64 last_check_time = 0; if (!s_cd) return; if ((timer_query() - last_check_time) >= F2_0) { if ((SDL_CDStatus(s_cd) == CD_STOPPED) && redbook_finished_hook) { con_printf(CON_VERBOSE, "RBAudio: Playback done, calling finished-hook\n"); redbook_finished_hook(); } last_check_time = timer_query(); } } // plays tracks first through last, inclusive int RBAPlayTracks(int first, int last, void (*hook_finished)(void)) { if (!s_cd) return 0; if (CD_INDRIVE(SDL_CDStatus(s_cd))) { redbook_finished_hook = hook_finished; con_printf(CON_VERBOSE, "RBAudio: Playing tracks %i to %i\n", first, last); return SDL_CDPlayTracks(s_cd, first - 1, 0, last - first + 1, 0) == 0; } return 0; } // return the track number currently playing. Useful if RBAPlayTracks() // is called. Returns 0 if no track playing, else track number int RBAGetTrackNum() { if (!s_cd) return 0; if (SDL_CDStatus(s_cd) != CD_PLAYING) return 0; return s_cd->cur_track + 1; } int RBAPeekPlayStatus() { if (!s_cd) return 0; if (SDL_CDStatus(s_cd) == CD_PLAYING) return 1; else if (SDL_CDStatus(s_cd) == CD_PAUSED) // hack so it doesn't keep restarting paused music return -1; return 0; } static int cddb_sum(int n) { int ret; /* For backward compatibility this algorithm must not change */ ret = 0; while (n > 0) { ret = ret + (n % 10); n = n / 10; } return (ret); } unsigned long RBAGetDiscID() { int i, t = 0, n = 0; if (!s_cd) return 0; /* For backward compatibility this algorithm must not change */ i = 0; while (i < s_cd->numtracks) { n += cddb_sum(s_cd->track[i].offset / CD_FPS); i++; } t = (s_cd->track[s_cd->numtracks].offset / CD_FPS) - (s_cd->track[0].offset / CD_FPS); return ((n % 0xff) << 24 | t << 8 | s_cd->numtracks); } void RBAList(void) { int i; if (!s_cd) return; for (i = 0; i < s_cd->numtracks; i++) con_printf(CON_VERBOSE, "RBAudio: CD track %d, type %s, length %d, offset %d", s_cd->track[i].id, (s_cd->track[i].type == SDL_AUDIO_TRACK) ? "audio" : "data", s_cd->track[i].length, s_cd->track[i].offset); } dxx-rebirth-0.58.1-d1x/arch/sdl/timer.c000066400000000000000000000021741217717257200175410ustar00rootroot00000000000000/* * * SDL library timer functions * */ #include #include "maths.h" #include "timer.h" #include "config.h" static fix64 F64_RunTime = 0; void timer_update(void) { static ubyte init = 1; static fix64 last_tv = 0; fix64 cur_tv = SDL_GetTicks()*F1_0/1000; if (init) { last_tv = cur_tv; init = 0; } if (last_tv < cur_tv) // in case SDL_GetTicks wraps, don't update and have a little hickup F64_RunTime += (cur_tv - last_tv); // increment! this value will overflow long after we are all dead... so why bother checking? last_tv = cur_tv; } fix64 timer_query(void) { return (F64_RunTime); } void timer_delay(fix seconds) { SDL_Delay(f2i(fixmul(seconds, i2f(1000)))); } // Replacement for timer_delay which considers calc time the program needs between frames (not reentrant) void timer_delay2(int fps) { static u_int32_t FrameStart=0; u_int32_t FrameLoop=0; while (FrameLoop < 1000/(GameCfg.VSync?MAXIMUM_FPS:fps)) { u_int32_t tv_now = SDL_GetTicks(); if (FrameStart > tv_now) FrameStart = tv_now; if (!GameCfg.VSync) SDL_Delay(1); FrameLoop=tv_now-FrameStart; } FrameStart=SDL_GetTicks(); } dxx-rebirth-0.58.1-d1x/arch/sdl/window.c000066400000000000000000000116001217717257200177220ustar00rootroot00000000000000/* * A 'window' is simply a canvas that can receive events. * It can be anything from a simple message box to the * game screen when playing. * * See event.c for event handling code. * * -kreator 2009-05-06 */ #include "gr.h" #include "window.h" #include "u_mem.h" #include "dxxerror.h" struct window { grs_canvas w_canv; // the window's canvas to draw to int (*w_callback)(window *wind, d_event *event, void *data); // the event handler int w_visible; // whether it's visible int w_modal; // modal = accept all user input exclusively void *data; // whatever the user wants (eg menu data for 'newmenu' menus) struct window *prev; // the previous window in the doubly linked list struct window *next; // the next window in the doubly linked list }; static window *FrontWindow = NULL; static window *FirstWindow = NULL; window *window_create(grs_canvas *src, int x, int y, int w, int h, int (*event_callback)(window *wind, d_event *event, void *data), void *data) { window *wind; window *prev = window_get_front(); d_event event; MALLOC(wind, window, 1); if (wind == NULL) return NULL; Assert(src != NULL); Assert(event_callback != NULL); gr_init_sub_canvas(&wind->w_canv, src, x, y, w, h); wind->w_callback = event_callback; wind->w_visible = 1; // default to visible wind->w_modal = 1; // default to modal wind->data = data; if (FirstWindow == NULL) FirstWindow = wind; wind->prev = FrontWindow; if (FrontWindow) FrontWindow->next = wind; wind->next = NULL; FrontWindow = wind; if (prev) WINDOW_SEND_EVENT(prev, EVENT_WINDOW_DEACTIVATED); WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); return wind; } int window_close(window *wind) { window *prev; d_event event; int (*w_callback)(window *wind, d_event *event, void *data) = wind->w_callback; if (wind == window_get_front()) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_DEACTIVATED); // Deactivate first event.type = EVENT_WINDOW_CLOSE; con_printf(CON_DEBUG, "Sending event EVENT_WINDOW_CLOSE to window of dimensions %dx%d\n", (wind)->w_canv.cv_bitmap.bm_w, (wind)->w_canv.cv_bitmap.bm_h); if (window_send_event(wind, &event)) { // User 'handled' the event, cancelling close if (wind == window_get_front()) { WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); } return 0; } if (wind == FrontWindow) FrontWindow = wind->prev; if (wind == FirstWindow) FirstWindow = wind->next; if (wind->next) wind->next->prev = wind->prev; if (wind->prev) wind->prev->next = wind->next; if ((prev = window_get_front())) WINDOW_SEND_EVENT(prev, EVENT_WINDOW_ACTIVATED); d_free(wind); event.type = EVENT_WINDOW_CLOSED; w_callback(wind, &event, NULL); // callback needs to recognise this is a NULL pointer! return 1; } int window_exists(window *wind) { window *w; for (w = FirstWindow; w && w != wind; w = w->next) {} return w && w == wind; } // Get the top window that's visible window *window_get_front(void) { window *wind; for (wind = FrontWindow; (wind != NULL) && !wind->w_visible; wind = wind->prev) {} return wind; } window *window_get_first(void) { return FirstWindow; } window *window_get_next(window *wind) { return wind->next; } window *window_get_prev(window *wind) { return wind->prev; } // Make wind the front window void window_select(window *wind) { window *prev = window_get_front(); d_event event; Assert (wind != NULL); if (wind == FrontWindow) return; if ((wind == FirstWindow) && FirstWindow->next) FirstWindow = FirstWindow->next; if (wind->next) wind->next->prev = wind->prev; if (wind->prev) wind->prev->next = wind->next; wind->prev = FrontWindow; FrontWindow->next = wind; wind->next = NULL; FrontWindow = wind; if (window_is_visible(wind)) { if (prev) WINDOW_SEND_EVENT(prev, EVENT_WINDOW_DEACTIVATED); WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); } } void window_set_visible(window *wind, int visible) { window *prev = window_get_front(); d_event event; wind->w_visible = visible; wind = window_get_front(); // get the new front window if (wind == prev) return; if (prev) WINDOW_SEND_EVENT(prev, EVENT_WINDOW_DEACTIVATED); if (wind) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); } int window_is_visible(window *wind) { return wind->w_visible; } grs_canvas *window_get_canvas(window *wind) { return &wind->w_canv; } extern void window_update_canvases(void) { window *wind; for (wind = FirstWindow; wind != NULL; wind = wind->next) gr_init_sub_bitmap (&wind->w_canv.cv_bitmap, wind->w_canv.cv_bitmap.bm_parent, wind->w_canv.cv_bitmap.bm_x, wind->w_canv.cv_bitmap.bm_y, wind->w_canv.cv_bitmap.bm_w, wind->w_canv.cv_bitmap.bm_h); } int window_send_event(window *wind, d_event *event) { return wind->w_callback(wind, event, wind->data); } void window_set_modal(window *wind, int modal) { wind->w_modal = modal; } int window_is_modal(window *wind) { return wind->w_modal; } dxx-rebirth-0.58.1-d1x/arch/win32/000077500000000000000000000000001217717257200164315ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/win32/d1x-rebirth.ico000066400000000000000000001642761217717257200212760ustar00rootroot00000000000000xx ¨è(xð á  L`~ÿK_}ÿK^|ÿK^|ÿK^|ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ^{ÿJ_|ÿJZsÿ8Rdÿ#U}ÿ*Qÿ/?{ÿ3.wÿ-Azÿ*Q~ÿ,J}ÿ-I}ÿ-N}ÿ,O}ÿ,I}ÿ,J}ÿ-N}ÿ+S}ÿ)X}ÿ)Y}ÿ*X}ÿ*Z~ÿ']~ÿ(\~ÿ)Z}ÿ)]~ÿ*_~ÿ(`~ÿ&`~ÿ'^~ÿ*Z~ÿ+\~ÿ(b~ÿ'd~ÿ'e~ÿ(f~ÿ(e~ÿ'h~ÿ)b~ÿ+]~ÿ)`~ÿ&c~ÿ&c}ÿ)[}ÿ+U}ÿ+T}ÿ*V}ÿ+U}ÿ,Q}ÿ+N}ÿ04}ÿ13}ÿ,E}ÿ)K}ÿ(L}ÿ(M}ÿ(K}ÿ)K}ÿ'N}ÿ(N}ÿ'O}ÿ'Q}ÿ%W~ÿ#V{ÿL`~ÿL`~ÿL`~ÿL`ÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLaÿLb€ÿL\wÿ8Teÿ"Zÿ*Vÿ0D~ÿ34{ÿ.E~ÿ+R€ÿ-Kÿ0Bÿ0Gÿ+Uÿ*Rÿ.Mÿ0Jÿ-Qÿ*Yÿ*Xÿ,Xÿ*^€ÿ(_€ÿ)\€ÿ*Zÿ*\€ÿ*b€ÿ)b€ÿ)_€ÿ)]€ÿ*^€ÿ+_€ÿ*c€ÿ'e€ÿ)d€ÿ*f€ÿ(i€ÿ'l€ÿ+e€ÿ,a€ÿ*c€ÿ(c€ÿ(c€ÿ*]ÿ-Wÿ,Vÿ*Xÿ,Vÿ-Sÿ,Nÿ11ÿ30ÿ-Cÿ)Lÿ+Hÿ+Kÿ*Gÿ)Jÿ(Qÿ)Oÿ*L€ÿ*O€ÿ&R€ÿ&QÿL`~ÿL`~ÿNb‚ÿUjÿUkÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUkŒÿUmÿUgƒÿ>R`ÿ#Rnÿ,Qtÿ.Frÿ0;qÿ09rÿ/>qÿ/:qÿ0.qÿ23qÿ,Kqÿ+Kqÿ0Cqÿ1>qÿ2@qÿ0Eqÿ/Fqÿ.Kqÿ+Rrÿ+Qrÿ,Mqÿ-Mqÿ,Qrÿ)Yrÿ*Vrÿ.Mrÿ+Trÿ'_rÿ)\rÿ,Wrÿ)Yrÿ(Xrÿ(\rÿ&brÿ&arÿ)]rÿ,\rÿ,Xrÿ,Urÿ+Wrÿ+Rqÿ-Nqÿ-Mqÿ+Mqÿ,Nqÿ.Kqÿ27qÿ6qÿ2(qÿ/9qÿ.:qÿ14qÿ/7qÿ1/qÿ.7qÿ.Cqÿ/>rÿ.>zÿ.D‚ÿ.A€ÿ.<~ÿL`~ÿMaÿFZuÿ/;Oÿ/;Mÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Nÿ/;Mÿ+Ppÿ#€¼ÿ$}²ÿ%|°ÿ'q°ÿ(e°ÿ(e°ÿ'l°ÿ(q°ÿ)s°ÿ)w°ÿ'w°ÿ(v°ÿ'w°ÿ)u°ÿ*u°ÿ*{°ÿ(}°ÿ(|°ÿ(~°ÿ(}°ÿ'|°ÿ'±ÿ&‰±ÿ(ˆ±ÿ,„±ÿ(‹±ÿ$“±ÿ&±ÿ(†°ÿ(…°ÿ&ˆ±ÿ%Œ±ÿ%ޱÿ&±ÿ&‘±ÿ&Œ±ÿ'†±ÿ'‡±ÿ(ˆ°ÿ*…±ÿ'‚°ÿ'|°ÿ(|°ÿ&|°ÿ&y°ÿ(^°ÿ+O¯ÿ*f°ÿ&o°ÿ(n°ÿ+q°ÿ*r°ÿ.p°ÿ-t°ÿ&r²ÿ'j°ÿ,V’ÿ.Gzÿ.M€ÿ-I}ÿL`~ÿMb€ÿ>Ogÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿN{ÿ ´üÿ«øÿ ±ùÿ!¯ùÿ ©ùÿ¨ùÿ°ùÿ!¹ùÿ#ºùÿ$¶ùÿ#µùÿ!´ùÿ!²ùÿ ¯ùÿ ³ùÿ ¹ùÿ ºùÿ"¹ùÿ#¹ùÿ!¸ùÿ¶ùÿ!ºùÿ"»ùÿ"Àøÿ&Ìøÿ'Ïøÿ$Èøÿ!Ãøÿ"Âùÿ%Äùÿ'Åøÿ$Åøÿ!Æøÿ)Ñøÿ*Ðøÿ"Áøÿ'Åøÿ(Ìøÿ$Æùÿ#Åøÿ!Àùÿ ¸ùÿ"¹ùÿ ´ùÿ¦ùÿ“ùÿ˜ùÿ!«ùÿ«ùÿ«ùÿ ·ùÿ$Áùÿ&Áùÿ&¾ùÿ ´ùÿ«ôÿ(u¯ÿ.Irÿ(Wÿ(T}ÿL`~ÿMb€ÿ>Neÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Ixÿ³þÿ¯ÿÿ¯ÿÿ³ÿÿ¶ÿÿ´ÿÿºÿÿ¾ÿÿ!¿ÿÿ#Àÿÿ!»ÿÿ·ÿÿ!µÿÿ ²ÿÿ·ÿÿ¹ÿÿ¹ÿÿ!»ÿÿ"¾ÿÿ!¾ÿÿ¼ÿÿ!¾ÿÿ!¾ÿÿ&Èÿÿ(Õÿÿ&Ôÿÿ"ÊÿÿÄÿÿ!Çÿÿ%Êÿÿ(Íÿÿ'Ñÿÿ#Óÿÿ*Ûÿÿ+Öÿÿ!Åÿÿ%Êÿÿ'Ïÿÿ#Éÿÿ#Íÿÿ$Ìÿÿ#Äÿÿ"Áÿÿ¹ÿÿ­ÿÿ¨ÿÿ¬ÿÿ²ÿÿ¯ÿÿ±ÿÿ"¿ÿÿ&Çÿÿ"Àÿÿ ºÿÿ»ÿÿ´úÿ(u²ÿ.Cqÿ*Qÿ*N}ÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿFuÿ ®þÿ§ÿÿ¥þÿ«þÿ ±þÿ"¶þÿ$¹þÿ%¼ÿÿ"¼ÿÿ!½ÿÿ#¹ÿÿ²þÿ «þÿ §þÿ!±þÿ³þÿ¬þÿ°þÿ"ºþÿ!¹þÿ ºþÿ »þÿ$Àþÿ)Éÿÿ%Ìÿÿ"Éÿÿ Ãÿÿ"Æÿÿ#Èÿÿ#Äÿÿ#Åÿÿ#Ëÿÿ'Òÿÿ-×ÿÿ)Ïÿÿ#Åÿÿ!Ãÿÿ%Èÿÿ%Êÿÿ"Ãÿÿ#Àÿÿ"½ÿÿ#»þÿ#»ÿÿ!µþÿ!°þÿ«þÿ ¨þÿ£þÿ¥þÿ¦þÿ ªþÿªþÿ¨þÿ¬ÿÿ¥ùÿ&q°ÿ-Dqÿ+Pÿ*O}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Ctÿ§þÿ¨ÿÿ ¬þÿ©þÿ«þÿ$ºþÿ%»ÿÿ%½ÿÿ$Áÿÿ"¿ÿÿ#½ÿÿ"·þÿ§þÿ ¢þÿ"°þÿ­þÿ¡þÿ­þÿ ·þÿ"¹þÿ#Áÿÿ!»ÿÿ¸þÿ$Æÿÿ&Îÿÿ#Ëÿÿ#Ëÿÿ%Ìÿÿ%Êÿÿ!ÄÿÿÁÿÿ Åÿÿ"Ëÿÿ%Ëÿÿ%Èÿÿ$Çÿÿ Âÿÿ"Äÿÿ'Ëÿÿ$Åÿÿ!»þÿ ¸þÿ²þÿ"¶þÿ!±þÿ!¯þÿ!®þÿ ªþÿ £þÿ™þÿ‘ûÿ˜ýÿšþÿ˜üÿ¢ÿÿžùÿ&i°ÿ,Drÿ,Jÿ-C}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Cxÿ¥þÿ¥ÿÿ°þÿ ±þÿ¯þÿ#»þÿ$½þÿ"»ÿÿ$Áÿÿ#Âÿÿ$½ÿÿ­þÿ˜üÿ—ûÿ!¥þÿ¢þÿ¦þÿ±þÿ«þÿ®þÿ#¼þÿ´þÿ°þÿ"¿þÿ$Éÿÿ$Êÿÿ%Íÿÿ%Îÿÿ%Ëÿÿ$Éÿÿ&Ëÿÿ&Ðÿÿ#Ìÿÿ Âÿÿ#Åÿÿ&Êÿÿ"Áÿÿ¾ÿÿ#Çÿÿ(Ìÿÿ(Çÿÿ!µþÿ¬þÿ °þÿ!¯þÿ ªþÿ!«þÿ#±þÿ ¤þÿ›þÿ“ýÿ!šýÿ!šþÿ˜þÿ¡ÿÿ!£ùÿ(l±ÿ.7qÿ02uÿ2)oÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 4Zÿôÿ›ÿÿ¤ÿÿ©þÿ¬þÿ±þÿ´þÿ#»ÿÿ µÿÿ¦þÿ¯ÿÿ&»þÿ%±ýÿ!Ÿþÿ“þÿ“þÿžþÿ¨þÿ¬þÿ¯þÿ ·ÿÿ'Åÿÿ,Ìÿÿ&Ãÿÿ ¾ÿÿ ½ÿÿ ¾ÿÿ"Âÿÿ"Ãÿÿ!Àÿÿ#Äÿÿ"Èÿÿ!Çÿÿ#Éÿÿ%Éÿÿ$Çÿÿ$Åÿÿ(Ëÿÿ(Íÿÿ"¿ÿÿ³ÿÿ#¸ÿÿ%»ÿÿ$µþÿ!«þÿ!£ýÿ"¦ýÿ%±þÿ"¯þÿ þÿ—ýÿùÿ•ùÿ#¦þÿ ¥ÿÿ ùÿ&e°ÿ-3oÿ.2tÿ..nÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 0Sÿ‚ãÿ˜þÿ¦ÿÿ«þÿ¦þÿªþÿ ´þÿ!¹þÿ%½ÿÿ!°þÿšüÿŸúÿ ¢ûÿ•üÿŽüÿœþÿ «þÿ§þÿ¨þÿ ²þÿ!·þÿ#½ÿÿ!½ÿÿ ¼þÿ"¿ÿÿ"½ÿÿ"¾ÿÿ"¿ÿÿ"¿ÿÿ$Äÿÿ'Ëÿÿ&Ïÿÿ$Íÿÿ"Åþÿ!¿ÿÿ ½ÿÿ Àÿÿ#Ãÿÿ(Éÿÿ%Æÿÿ"Àÿÿ(Àÿÿ&½ÿÿ#µþÿ#«þÿ˜ýÿ—ýÿ!©þÿ ªþÿ!¤þÿ þÿ!šþÿ‹øÿ‰ñÿ‘øÿ “øÿ&c²ÿ,0jÿ0(fÿ/#`ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 8_ÿôÿ˜ûÿ¥ÿÿ¨ÿÿ ±ÿÿ°ÿÿ±ÿÿ²ÿÿ#Àÿÿ#µûÿˆòÿŠöÿšþÿ“þÿ”ýÿ!¥þÿ ²þÿ±þÿ"µþÿ ¶þÿ¯þÿ¬þÿ¯þÿ ºþÿ(Èÿÿ)Çÿÿ"¼ÿÿ!»ÿÿ$Àÿÿ#Àÿÿ#Äÿÿ&Ïÿÿ$Îÿÿ Ãÿÿ$Áÿÿ²þÿ¯ÿÿ´þÿ¸þÿ$Âÿÿ&Ãÿÿ(Áÿÿ'¼ÿÿ%·þÿ"°þÿ £þÿ›þÿ þÿ ­þÿ#¬þÿ¡þÿ!žÿÿ ûÿ…ìÿ…íÿõÿ&a³ÿ.'gÿ0]ÿ/VÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@fÿ'—úÿ#•õÿ$¡÷ÿ&©øÿ#­ùÿ¬ûÿ³þÿ³þÿ¯þÿ®ÿÿ©þÿžþÿ–ÿÿþÿ“ýÿþÿ¦þÿ ´þÿ&½ÿÿ$¼ÿÿ!·þÿ µþÿ ¶þÿ!ºÿÿµÿÿ ¹þÿ!¹ÿÿ³þÿ!»þÿ »ÿÿ"¿ÿÿ'Êþÿ!Äþÿ Áÿÿ%Çÿÿ ·þÿ¯ÿÿ!·ÿÿ#¼ÿÿ&Ãÿÿ%Ãÿÿ$¼ÿÿ$·ÿÿ%¸ÿÿ ­þÿ#²þÿ!®þÿ¯þÿ"¸þÿ ¯þÿžþÿ‘ûÿ–üÿ —úÿ ûÿ ™ùÿ&W±ÿ.)qÿ,2wÿ+.pÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿÿ!ÿ&ÿ)ÿ+ÿ6EOÿC‰ÈÿA…Äÿ>‹Éÿ@šÓÿ;£×ÿ7¨Ýÿ0©äÿ,¬ëÿ(°ðÿ$­õÿ"®ûÿ"ªýÿ¦þÿŸÿÿÿÿ¥þÿ¬þÿ#¶þÿ'¼þÿ%»þÿ$¼þÿ#¼þÿ ¶þÿ¨þÿ›þÿ®þÿ#¼ÿÿ²þÿ"·þÿ#½ÿÿ »ÿÿ!¿ÿÿ$Åÿÿ%Çÿÿ$Èÿÿ#Åÿÿ#Àþÿ#ºþÿ&¾ÿÿ'Äÿÿ&Æÿÿ#ºþÿ ±þÿ"¸ÿÿ#·þÿ$¶þÿ#¶þÿ"µþÿ ·þÿ¤þÿšþÿ“üÿûÿ›ÿÿ#´ÿÿ «ùÿ&j°ÿ-8rÿ,Aÿ+?}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ"ÿ,ÿ7ÿD#ÿQ)ÿZ-ÿb0ÿi4ÿn7ÿq:ÿxY0ÿ€yÿ|{tÿwxvÿr{ÿm„ŠÿfŒ”ÿ\‰žÿS’­ÿK¡¾ÿ?¡Ìÿ5›Ùÿ.¤åÿ+®îÿ&¬öÿ#«ûÿ ­þÿ ±ÿÿ ±ÿÿ!²þÿ³þÿ!·þÿ'¿ÿÿ&¾ÿÿ!¸þÿ°þÿ°þÿ$»ÿÿ%»ÿÿ"¸þÿ$»ÿÿ$½þÿ%Àÿÿ&Äÿÿ$Èÿÿ"Ëÿÿ$Ìÿÿ$Åþÿ!²þÿ"°ÿÿ!ºÿÿ%Äÿÿ$Âþÿ ¿ÿÿ"Áÿÿ'Åÿÿ&¼þÿ£þÿ¢ýÿ¦þÿ¤þÿ­þÿ"±þÿ ÿÿ¡þÿ ´ÿÿ°ùÿ(t°ÿ.Cqÿ+Kÿ*I}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿ*ÿ<ÿO'ÿ`1ÿr:ÿDÿŽLÿ˜Qÿ¢Y ÿ¥] ÿ©` ÿªcÿ¦aÿ¨gÿ©m&ÿ¨m%ÿ¬t,ÿ±}3ÿ·†4ÿ·‘FÿªSÿ˜…Tÿ‰†fÿy‰zÿk‘ÿ[“¨ÿLœ½ÿ?¤Ñÿ6­àÿ-¯îÿ&°öÿ¬ûÿ®þÿµþÿ¯þÿ²þÿ#¾þÿ)Èÿÿ&Áþÿ°þÿ$¶þÿ&»ÿÿ!µþÿ$¼þÿ%Áÿÿ&Áÿÿ&Ãÿÿ!Äÿÿ Èÿÿ"Êÿÿ#Ãþÿ£þÿ‘þÿ¦þÿ!¸þÿ%¿ÿÿ%Æÿÿ$Âÿÿ"¸þÿ§ÿÿ‹üÿ‰úÿ’ýÿ™þÿ!°ýÿ&¿þÿ"¹þÿ±þÿºÿÿ!¶ùÿ*u°ÿ0?qÿ,Jÿ+I}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ&ÿ:ÿU+ÿn9ÿ‚Eÿ”Pÿ¢Wÿºvÿ·ÿ·qÿ­nÿ´z%ÿ°x(ÿ©q'ÿ©t(ÿ¢o)ÿžk%ÿŸiÿ©s ÿ·ˆ5ÿˤXÿèÀXÿýá[ÿøà]ÿèÆXÿÚ§CÿÄ~'ÿªu4ÿ•xKÿ†}fÿwŠ‚ÿb˜ŸÿM»ÿ<¡Óÿ/§åÿ(°òÿ&ºúÿ ·þÿ²ÿÿµÿÿ%Ãþÿ(Çÿÿ¶ÿÿ&ºþÿ&¼ÿÿ°þÿ!¸þÿ%Áÿÿ#½ÿÿ!½ÿÿ"Ãÿÿ$Êÿÿ#Êþÿ·þÿ“þÿŒþÿ¦þÿ¦ýÿ”üÿ¥þÿ µþÿ¨þÿ˜þÿ–ýÿ –üÿŠúÿŽóÿ"³ýÿ#·þÿµþÿ°þÿ¼ÿÿ#ºùÿ*y°ÿ.Aqÿ+Jÿ*J}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1ÿI#ÿh2ÿ†EÿšTÿ¦_ ÿªeÿ¦iÿ¯p#ÿÕ¨>ÿæµCÿ¸€/ÿ®{-ÿ²€/ÿ§w+ÿŸn(ÿ¤p)ÿªt*ÿ§q)ÿ¨u*ÿ¼ˆ0ÿÈ¢HÿÜÏÿñò·ÿÿÿšÿÿÿ–ÿÿÿËÿÿé‚ÿâ“ÿ¹lÿ¦fÿ¦hÿ¨r*ÿ }CÿŒ†bÿr‡ÿW™ªÿD¦Éÿ7´âÿ,»ñÿ$ºúÿ ¹ÿÿ$Åÿÿ%Ìÿÿ#Âÿÿ#¾þÿ#½ÿÿ!¸þÿ%Àÿÿ$¾þÿºþÿ¾ÿÿ Âÿÿ!Áÿÿ$Åþÿ#ºþÿ¡þÿ§þÿ ³þÿ£ýÿŠüÿ•ýÿ"³þÿ ²þÿªþÿ"³þÿ$¶ÿÿ öÿ‡êÿ¥üÿ£þÿ ±þÿ ¹þÿ¸ÿÿ²ùÿ(t°ÿ/@qÿ+Jÿ*J}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6ÿT+ÿs9ÿ™R ÿ̈,ÿÕŽ*ÿ³qÿ›h#ÿ”g'ÿ“h)ÿ¬v.ÿå­>ÿðµCÿÛ¢<ÿÞ±CÿÓ–3ÿ©s*ÿ o)ÿ§s*ÿ®w+ÿ¹/ÿ¶~/ÿ·}+ÿÙ¤9ÿúæmÿûü£ÿþýÿþÿ²ÿÿýÍÿøÛlÿ×™-ÿ®w.ÿ—g$ÿ•aÿ¤fÿ´nÿ°mÿ¥r.ÿ˜‚Oÿ€’yÿa ¥ÿI­Çÿ6¹âÿ-Áóÿ'Äüÿ¿þÿ»ÿÿ#Àþÿ#¾ÿÿ$¿þÿ'Áýÿ«úÿ­ûÿ!Áÿÿ#Äÿÿ!¹ÿÿ!·ÿÿ&¼þÿ#³þÿ¨þÿ¬þÿ ´þÿ"­þÿ#°þÿ%¸þÿ!ºþÿ#Àÿÿ#¾þÿ ºþÿºþÿ°üÿ¤ýÿ‘üÿ ©þÿ%»ÿÿ²ÿÿ°ùÿ'u°ÿ0Aqÿ-Kÿ*M}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ2ÿU*ÿ|Aÿ–Kÿ¸iÿæµsÿÿìÿäµMÿ©t(ÿ™k'ÿšk'ÿšj'ÿ¦n(ÿá§>ÿý×Rÿÿêmÿÿó›ÿûÇTÿȆ,ÿªv+ÿ¦r,ÿ«w-ÿÈ6ÿØ–7ÿÍ0ÿå¨>ÿÿèxÿÿÿ•ÿÿÿzÿÿÿ°ÿÿúÿûÓBÿâ¢<ÿ»…7ÿ¢n'ÿžk(ÿ£t+ÿ¥w+ÿhÿ¢bÿ´mÿ±v'ÿš€Hÿ“vÿa¥¦ÿE³Îÿ2ºèÿ'ºõÿ#¼üÿ"Àÿÿ »ÿÿ&Äÿÿ-Åþÿ§÷ÿ¦øÿ$ºÿÿ"¶ÿÿ¨þÿ¥þÿ°þÿ#ºþÿ´þÿ¶þÿ!ºþÿ!¾þÿ"¾þÿ!¹þÿ ¸þÿ$Áÿÿ"Àÿÿ ¾þÿ"Âÿÿ$Åÿÿ µþÿ©ýÿ±þÿ­ÿÿ°ÿÿ³ùÿ'{°ÿ2Aqÿ/Kÿ,O}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ)ÿM&ÿw=ÿ™Rÿ£^ÿ«_ÿÚ¨Sÿÿÿéÿÿò¥ÿΕ1ÿ¥n!ÿª2ÿ­~1ÿ o*ÿl'ÿ¹2ÿàºFÿùåiÿÿÿâÿÿï›ÿî´>ÿÌ3ÿ®t+ÿ´{,ÿÖ™6ÿ÷ÃMÿùÙnÿúç›ÿÿüÂÿÿú•ÿÿ÷oÿþø¡ÿÿü¨ÿ÷×bÿÔ’2ÿ³y,ÿ¨t+ÿ n(ÿ¡r)ÿ¥w,ÿžp+ÿ˜j'ÿ¡j"ÿ¥dÿ¥bÿ¨p$ÿ™‚Kÿz—ÿZ­³ÿ@¹×ÿ.¹îÿ"´ùÿ²þÿ!ºÿÿ&¾ÿÿ&¿ÿÿ#ºþÿ¬þÿ¢þÿ¤þÿ­þÿ¶þÿ$¾ÿÿ$Âþÿ&Ãÿÿ#¼þÿ ·þÿ!¹þÿ ³þÿ´þÿ$¼ÿÿ!ºÿÿ#Âÿÿ'Èÿÿ#½ÿÿ ¶þÿ"·þÿ!¸ÿÿ§þÿ©ÿÿªùÿ*w°ÿ2Dqÿ.Pÿ,P}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ;ÿg5ÿ“Mÿª` ÿ¦hÿ‘a$ÿ¥jÿå½_ÿÿüÎÿÿñ«ÿã¯Jÿµ|)ÿ©|1ÿ©z1ÿ£r,ÿ¦u.ÿ¦r,ÿ·s-ÿÞ—2ÿþñ”ÿÿÿØÿÿð¦ÿõËlÿÑ•7ÿÙŸ@ÿðÅlÿÿñ¡ÿÿÿµÿÿùºÿýå‘ÿôËLÿé»IÿñÈXÿÿô—ÿíÐ{ÿ¼~(ÿ¨o'ÿ§t-ÿšk(ÿ˜h'ÿœk(ÿžm'ÿŸm'ÿ m)ÿ˜h'ÿ_ÿ›^ÿ§dÿ©t*ÿ“‰[ÿmŸ•ÿK¯Æÿ1²åÿ#±ôÿ´üÿ³þÿ¸ÿÿ!¹ÿÿ¯þÿ³þÿ"¹þÿ"½þÿ$¿þÿ&Æÿÿ$½þÿ¢ýÿ!®þÿ$¹þÿ#¸þÿ °þÿ ²þÿ#·þÿ ´þÿ ºÿÿ$¿ÿÿ!·ÿÿ¯þÿ ®þÿ!®þÿ®þÿ¯ÿÿ©ùÿ*s°ÿ.Iqÿ,Uÿ,O}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&ÿO'ÿBÿ¤Z ÿªhÿi#ÿ‘f(ÿ“g(ÿ±x*ÿá¦0ÿü×gÿÿþ¶ÿýãŠÿÌ“;ÿ¦o(ÿžn*ÿ¡r-ÿ¥t/ÿ¦u/ÿ«y2ÿLJ4ÿñÅAÿþôœÿÿÿæÿÿÿÃÿûå}ÿÿë–ÿÿÿÒÿÿýËÿÿÖuÿùºNÿí§:ÿÚŽ0ÿÑ…-ÿæ«Gÿÿï“ÿìÇlÿ»*ÿ©v.ÿ¡s-ÿœn*ÿœl)ÿšj(ÿ™i(ÿ™k'ÿ›l'ÿœl'ÿ—h'ÿc&ÿ“`ÿ¢bÿ¯jÿ¢{<ÿ“wÿW§³ÿ9°Ûÿ'°ñÿ ³ûÿ´þÿ³þÿ!ºÿÿ'Çÿÿ%Äþÿ"¼ÿÿ#»þÿ ¶þÿ °ÿÿšüÿ¨þÿ%½ÿÿ#¼þÿ ¶þÿ°þÿ"µþÿ¯þÿ ¹þÿ#¼ÿÿ­þÿ—þÿ–ýÿ¢þÿ§þÿ"·ÿÿ"³ùÿ'u°ÿ,Fqÿ,O€ÿ,J~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ0ÿb0ÿ–Nÿ­dÿ§kÿ™i(ÿ”h(ÿ—h&ÿžm&ÿµ€2ÿÕŽ/ÿò«#ÿÿò”ÿÿõ«ÿå¯TÿÀˆ3ÿ¬y0ÿ©w2ÿªx1ÿ¬z2ÿ±€5ÿ¼ˆ9ÿÏ4ÿí½?ÿúÜ|ÿöâ’ÿùìŽÿÿö©ÿþì¤ÿüÕnÿø«1ÿð3ÿâ›<ÿßš@ÿë°Cÿößÿÿø»ÿòÄiÿʇ)ÿ¯{2ÿ¤v/ÿ£s/ÿ¡r-ÿ p,ÿŸo,ÿn+ÿ›m)ÿ›k(ÿšj&ÿ—h&ÿ–h'ÿ“f$ÿ›aÿ§cÿªq%ÿ“Œ^ÿf ¡ÿ=¨Óÿ+´íÿ#·ûÿ³þÿ!¼ÿÿ µÿÿ­þÿ±ÿÿ"¹ÿÿ ýÿœýÿ°ýÿ ¸ýÿ$¾ÿÿ"¾ÿÿ!¼þÿ²þÿ¯ÿÿ´þÿ!¸þÿ!¶þÿ©þÿšþÿŽýÿúÿ›þÿ!­ÿÿ!¬ùÿ)k±ÿ14qÿ/;ÿ.:}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ<ÿq8ÿ¡Vÿ­hÿj%ÿ”g(ÿši'ÿžk'ÿl)ÿ¡n)ÿ±{.ÿɈ6ÿè§6ÿýëÿÿ÷®ÿøÅ_ÿÜ¡?ÿ¹„6ÿ­{3ÿ®{3ÿ«z3ÿ®|5ÿ®}5ÿ³}7ÿʉ7ÿÕ”.ÿÎ’.ÿÑ—?ÿæ­Kÿé¬9ÿæ¥8ÿàžIÿë«LÿõÁUÿúØbÿÿåaÿÿû–ÿÿûÉÿôÂdÿ͆'ÿ¯|4ÿ¨x1ÿ¦v0ÿ£t/ÿ¢t.ÿ§u/ÿ¨u.ÿ¤r,ÿŸn*ÿm*ÿœl(ÿšk&ÿ™j&ÿ–i(ÿ—e ÿ¢`ÿ¯mÿŸ„HÿršÿH®Èÿ0´êÿ#³ùÿ#¾ÿÿ²ÿÿ¨þÿ¬þÿ"¸þÿ¬ýÿýÿ²ÿÿ"¼þÿ!µýÿ ²þÿ"ºþÿ"·þÿ¬þÿ µþÿ°þÿ¯þÿ«þÿ!©þÿ™üÿ‰÷ÿ•ýÿ›ÿÿ™øÿ*]°ÿ3)oÿ1,zÿ1'xÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿE"ÿ@ÿ¨\ ÿ©hÿ—h&ÿe&ÿ•e%ÿžm(ÿ¥s,ÿ¦t-ÿ§t,ÿ®z/ÿ¼†5ÿÖ™6ÿóÊsÿÿ÷ŸÿúÑgÿÛ›=ÿ¶€4ÿ¨x3ÿ«z4ÿ«y5ÿ©y4ÿ©x4ÿ¯~7ÿ²~8ÿ®v4ÿ®w2ÿ´y/ÿ¿€/ÿLj8ÿÈŒ>ÿÆŽ?ÿÚ›BÿûÍ\ÿÿÿ‡ÿÿü†ÿÿøªÿÿüáÿö׉ÿÑ—1ÿ²{1ÿ©z4ÿ§x1ÿ¥v1ÿ¥v/ÿªy1ÿªx/ÿ£q-ÿ o,ÿ¤r-ÿ£r,ÿn*ÿšk'ÿ m'ÿŸn'ÿ“d#ÿ™^ÿªeÿ¥{7ÿ~˜ÿO¬Àÿ1°çÿ'µøÿ#ºþÿ"·ÿÿ ®ÿÿ"±þÿ#µþÿ#²þÿ"°þÿ"²þÿ”ûÿ‘üÿ ¯ÿÿ&¸þÿ§ÿÿŸýÿ«þÿ©þÿ¢þÿœþÿ–ýÿ’üÿ’ýÿˆýÿ†ïÿ)Uªÿ2)pÿ//zÿ.+xÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿH$ÿ‡Eÿ²gÿ®r"ÿ–h(ÿ‘d%ÿši%ÿši&ÿžn)ÿª{/ÿ«{0ÿ©w0ÿ­z0ÿ¯}3ÿÁ2ÿê 0ÿÿóÿúä€ÿÔ—<ÿµy.ÿ«v2ÿ«z6ÿ¯}8ÿ¯7ÿ®~7ÿ°~8ÿ®~7ÿ­8ÿ²‚:ÿ³‚;ÿ³ƒ<ÿ·„=ÿ¹†<ÿ¹†;ÿ¿†;ÿâªIÿÿìrÿÿÿ¥ÿÿýæÿÿÿÿÿþùÔÿîÊaÿĆ-ÿ«y2ÿª|5ÿ¨y3ÿ¦v1ÿ¨x1ÿ¨y1ÿ¢r.ÿ¢q-ÿ¥t.ÿ§v/ÿ¢q,ÿœl(ÿ¥v0ÿ¬6ÿŸr,ÿb$ÿ”]ÿ©bÿ­z.ÿ†–vÿO»ÿ/žäÿ&­öÿ!³þÿ©ÿÿ¤þÿ!¨ÿÿ$­þÿ#©ýÿ!¨þÿˆûÿ’üÿ¤þÿ!«þÿþÿˆúÿ›üÿžþÿ˜þÿþÿþÿ›ÿÿ’üÿ‡ûÿëÿ'Q¨ÿ1)qÿ/2zÿ.2wÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿJ%ÿ†Dÿ¨_ÿ¯v%ÿ©z/ÿžo)ÿ n(ÿ¢p*ÿœl(ÿm)ÿ¢s-ÿ§w/ÿ®{2ÿ±}3ÿ¯}3ÿ½„:ÿâ”&ÿüÛ„ÿÿ÷³ÿìÆdÿÛ¦=ÿÍ’6ÿº€2ÿ³}4ÿµ8ÿ´8ÿ´9ÿ³:ÿµ„<ÿ¶ƒ:ÿº‡=ÿ¾‹>ÿµ‚<ÿ¶ƒ;ÿ¹†<ÿ¸…=ÿʼn:ÿêµLÿÿ÷žÿÿÿóÿÿÿàÿÿÿÀÿýí–ÿÙ>ÿ¯w+ÿ¬}9ÿ®}5ÿ«z5ÿ©y3ÿ¨x2ÿ¦u1ÿ¢s/ÿ¤u0ÿ®}2ÿ©v.ÿŸn)ÿª9ÿ·Iÿ±‚6ÿžl%ÿ–g'ÿ¢k!ÿ¶oÿ¯u*ÿ‚oÿP•¹ÿ0žäÿõÿ¨þÿ£üÿ”ùÿ–üÿœýÿ ¡þÿ¡ýÿ!«þÿ›üÿ“ýÿùÿûÿ—ýÿ˜þÿ˜ýÿ þÿ¥ýÿ ¥þÿ˜ýÿ¡þÿ—öÿ&Y°ÿ2)mÿ2(uÿ1'rÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿF#ÿ‰Fÿ­eÿ£l#ÿžo*ÿ¢s*ÿ¤s*ÿ«z.ÿ¨u.ÿŸm*ÿn+ÿžn,ÿ§v0ÿ±~3ÿ·„6ÿ¾<ÿÅ’?ÿÑŠ1ÿí¯NÿýðºÿÿúÃÿþð”ÿøÖpÿâ±VÿΔ>ÿÈ‹6ÿlj3ÿÆ4ÿ¸€9ÿ¶„>ÿ¸„<ÿ½‰?ÿÀŒ@ÿ·„<ÿ¹‡=ÿÀŠ?ÿÆ‘Cÿ½‡>ÿÍ‘AÿøÑmÿÿð˜ÿùÜxÿøÚnÿþõ¶ÿíÌ~ÿć/ÿµ}7ÿ¹†<ÿ·…9ÿ°6ÿ©z4ÿ¨y4ÿ§w2ÿ¨x2ÿ¯}3ÿ¯{1ÿ¨u.ÿ¤v1ÿª}6ÿ®|1ÿ¤p(ÿk'ÿ¢t+ÿ§r$ÿ¬dÿªn&ÿ†qÿL’¼ÿ+‘çÿ$¥ûÿöÿ†íÿŠôÿ–þÿŸÿÿ!«ÿÿ"©ýÿ÷ÿ‡úÿúÿ"¡þÿ!¥þÿ£þÿ©ýÿ ¸þÿ%Âÿÿ¯þÿ þÿ¯ÿÿ£úÿ(_²ÿ4*oÿ1,xÿ1(vÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿB ÿƒBÿ«bÿ®x'ÿ¦y.ÿl'ÿ˜h&ÿœm)ÿ£s,ÿ¦u-ÿ£r-ÿ¡q.ÿ£t0ÿ¥v1ÿ«y2ÿ·‡9ÿÆ“@ÿÍ–@ÿÊ‹BÿÜ“ ÿöÛ“ÿÿÿüÿÿÿÝÿÿÿ´ÿÿõ¬ÿõÜ”ÿïÈuÿíÄoÿé¶WÿÒ—=ÿÁ‰Aÿ»‡?ÿº†?ÿ¹‡?ÿ»‡?ÿ¼‰@ÿÁ‹@ÿÈ’CÿÃCÿÅCÿÛ¡Gÿâ«EÿÝœ4ÿî³Kÿÿ÷Éÿý÷Ùÿí¼SÿÓ1ÿÄŠ@ÿ¿‹>ÿ¹…;ÿ¯~7ÿª{4ÿ¯7ÿ°~5ÿ§w1ÿ©x1ÿ¬y2ÿ£q,ÿœm)ÿžn*ÿm*ÿ™j&ÿ˜i&ÿ™j)ÿœg ÿ®jÿ¯w+ÿ||wÿHˆÂÿ-ãÿ ‰êÿïÿ’õÿ‘üÿ¡þÿ ©ÿÿüÿŠõÿŒúÿ šÿÿ þÿ£þÿ©þÿ$ºþÿ%Æÿÿ&Æÿÿ´þÿ«þÿ°ÿÿ¥ùÿ(d¯ÿ22rÿ/4}ÿ0/{ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ8ÿ|?ÿ§^ ÿ h ÿp+ÿ¤u*ÿœl'ÿœk(ÿžm*ÿœl*ÿ¢r-ÿ¥u/ÿ¦u1ÿ¦w1ÿ¥v1ÿ¨y3ÿ³‚8ÿÊ‘>ÿÓ™EÿÌ@ÿÑ‘,ÿõÝŒÿ÷é»ÿôÝ“ÿ÷æŠÿþô ÿÿÿ¹ÿÿÿ¾ÿÿÿÎÿÿõÌÿ÷Úzÿâ¦DÿÀ‰Bÿ¼‡@ÿ»‡@ÿ½ˆAÿ½‰@ÿ¿‹@ÿÁ‹@ÿÁŒBÿÃŽCÿÀ‡@ÿ½z3ÿΉ0ÿóÈjÿÿüÚÿÿÿýÿÿó£ÿôÂFÿØ–9ÿËAÿ½‰=ÿµƒ:ÿ¬}6ÿ®~6ÿ³€7ÿ±ƒ8ÿ¬6ÿ¦v2ÿ©x1ÿ§x0ÿžp,ÿœn+ÿšl(ÿ–g&ÿ–g&ÿ˜j(ÿ£l"ÿµkÿªp0ÿtxzÿ@q¯ÿ%rÈÿ‹äÿ’îÿ‰íÿŒñÿœúÿþÿ™üÿ˜ýÿšÿÿ™þÿ¡þÿ¥þÿ!¶þÿ$¼þÿ"¸þÿ¯þÿ¨þÿ®ÿÿ#¯ùÿ'n¯ÿ.6rÿ/3~ÿ//|ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ-ÿn7ÿ£Zÿ gÿc%ÿ“c"ÿœk'ÿ¤s+ÿ§t,ÿ¦u.ÿ¨x/ÿ§w0ÿ¥u0ÿ§w1ÿ©x2ÿ¬z3ÿ«{5ÿ±7ÿÉ‘?ÿÊ’BÿĆ6ÿÞ¶aÿ÷äÿÞµ[ÿÚž=ÿÞ¦Fÿâ°LÿñÉiÿù܆ÿÿèÿÿÿöÿÿÿÛÿûÏ^ÿÒ’Bÿ¿ŠEÿ¿ŠBÿ¿ŠBÿ¿‹BÿÀ‹CÿÁ‹CÿÁŒCÿ¾ˆ?ÿÀ„7ÿ͉3ÿæ°Xÿýô¿ÿÿÿÇÿÿÿ»ÿÿÿêÿÿóŸÿï¸CÿÌŠ8ÿ¾ˆ?ÿ¹‡<ÿ±9ÿ­{6ÿ¯}7ÿ»Œ>ÿ¼Ž>ÿ¬}5ÿ¨x2ÿ­|2ÿ©w/ÿ¤r.ÿ p,ÿ›l)ÿ™j'ÿl'ÿŸm*ÿ i ÿ­gÿŸl4ÿgjsÿ6f ÿ"q¿ÿtÇÿyÔÿ€ìÿúÿ¢þÿ!§ÿÿ›þÿ”ýÿ £þÿ ®þÿ©þÿ­þÿ!±þÿ!±þÿ¨þÿþÿ¤ÿÿ$§ùÿ&g°ÿ.1qÿ03~ÿ.0}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿ^.ÿTÿ¥gÿ“e'ÿ•f$ÿ o'ÿ§u-ÿªw/ÿ©w.ÿ±5ÿ¶ˆ8ÿ¬{3ÿ¤u0ÿ¨x2ÿ­|5ÿ±€7ÿ¯~8ÿ¯~8ÿ¸†=ÿ±x.ÿÊ›MÿôØ‹ÿß¶eÿÈ8ÿȈ=ÿÇ‹?ÿć<ÿÕ“?ÿã¡Cÿû·Kÿÿç–ÿÿÿñÿÿðµÿä¦AÿÀ†@ÿÀFÿÂŒCÿÃCÿÄŽFÿÂŒEÿÁ…=ÿÉ‹=ÿã®VÿöÖ}ÿÿòºÿÿÿàÿþéƒÿý×Zÿýê¶ÿÿÿèÿûä–ÿâŸ:ÿɆ5ÿ»‡?ÿ¶„<ÿµ‚:ÿ°}8ÿ³9ÿ½Š<ÿ·…8ÿ©x4ÿ¬y2ÿ«y1ÿ¦u0ÿ§v/ÿ¢q,ÿ›k(ÿ¢p)ÿ¥s*ÿ•i'ÿšdÿ¯iÿ–k=ÿ[p…ÿ1r°ÿk¸ÿwÕÿ÷ÿšÿÿ §þÿ!ªþÿ—þÿ–ýÿ#®þÿ#¶þÿ °þÿ®þÿ!³þÿ!³þÿ«þÿ¢þÿ¨ÿÿ!¥ùÿ&c°ÿ03rÿ07~ÿ/2}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿJ%ÿIÿ¨eÿŸn'ÿ£r*ÿ«|3ÿ°„;ÿ©y0ÿ n)ÿ¦t-ÿ¸‰;ÿ»Aÿ«}6ÿ¥v1ÿªz5ÿ¯~8ÿ³:ÿ±:ÿ±:ÿ¯=ÿ«n#ÿÛ·gÿþí¡ÿÓ¥Wÿ¼~3ÿ½‚9ÿ¼…?ÿ½ˆDÿÈEÿÕ•Fÿï©MÿþÀQÿÿìÿÿÿëÿñÎÿÎ6ÿ‡BÿÃGÿÅŽGÿÄ‹CÿÄ…;ÿÎBÿìÁqÿÿó³ÿÿûÅÿúí³ÿîÍ„ÿâªKÿÞ™;ÿãªNÿøà¦ÿÿÿÝÿúß–ÿè«HÿÉŠ6ÿ¹ƒ<ÿ»‰>ÿ´;ÿ®|8ÿ²8ÿ²7ÿ¬{5ÿªy3ÿ§v2ÿ¨v0ÿ­z2ÿ§v.ÿœm+ÿ¡p+ÿ©u*ÿ n(ÿšl(ÿ¦jÿ®kÿ‰w]ÿMx›ÿ)vÁÿ‡êÿ—ÿÿÿÿ¢þÿ§þÿ¡þÿ¥þÿ ²þÿ!·þÿ ¶þÿ±þÿ´þÿ³þÿ²þÿ«þÿ¯ÿÿ°ùÿ(o°ÿ17rÿ04|ÿ/.zÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ5ÿ|?ÿ§^ ÿi#ÿ£r*ÿ³/ÿ·Dÿ°ŠDÿŸp,ÿši'ÿ£q.ÿ°7ÿµˆ<ÿ­}7ÿ©y4ÿ¬{7ÿ±:ÿµ;ÿµƒ;ÿ·…<ÿµ„?ÿ²s*ÿÚ°[ÿþù³ÿôâ™ÿâ´dÿÌ–IÿÁ‹@ÿÂDÿÊ’HÿÕ›Lÿå§Rÿû³TÿÿÓ]ÿÿø³ÿýøÛÿíÀoÿÕ6ÿÍŒ?ÿÊŠ>ÿÎ>ÿܧSÿòØ‚ÿþï¥ÿñ×—ÿܲpÿÓžPÿÌ“>ÿÆŠ@ÿĉCÿÍ‹8ÿã¦IÿúÞ˜ÿÿÿÛÿþí¬ÿè³Nÿȉ3ÿ¼ˆ>ÿ¸†>ÿ²€:ÿ±€9ÿ°8ÿ­}6ÿ©y5ÿ§x3ÿ©x2ÿ«x1ÿªx0ÿ¢r-ÿžm+ÿ¦u,ÿ©w,ÿ¢q+ÿši&ÿ¦fÿ¦k%ÿtqgÿ=|·ÿ'‘îÿ˜ÿÿ‘ÿÿœþÿ¬þÿ±þÿ²þÿµþÿ¶þÿµþÿ²þÿ¸þÿ³þÿ¶þÿ ¶þÿ¶ÿÿ®ùÿ(q°ÿ34rÿ.2~ÿ-/|ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿa1ÿ Vÿ¡fÿ”h(ÿ¤q)ÿ«y.ÿ¬7ÿ¨~6ÿ£s-ÿ¥t.ÿ¤t1ÿ©w1ÿ¬|3ÿ¬z5ÿ­|7ÿ±~9ÿ´:ÿ¶ƒ;ÿ¹…;ÿ»‡?ÿ»ˆ@ÿ·€:ÿÍ“BÿõÙÿÿêÿüá•ÿôÞÿä»bÿЖHÿÍ“HÿØ›Nÿé©Rÿ÷±Xÿÿ¾YÿÿÜnÿÿÿ¼ÿÿöÒÿõËxÿé«Gÿä¨MÿïÄqÿüì¡ÿúç“ÿá¶gÿÍ‘Eÿƈ9ÿÇ;ÿÊAÿÄFÿÅFÿÆŽEÿÍŽ<ÿä¥EÿùÖ‰ÿÿÿÓÿýï²ÿå²WÿÁ‡8ÿ·„>ÿµ„<ÿµ‚;ÿ´‚;ÿ°€9ÿ«|7ÿªz5ÿ©y4ÿ§u1ÿ¦u/ÿ¢r.ÿœl+ÿ£u-ÿ¬~/ÿ¦u+ÿl*ÿ›h!ÿ¬eÿšm6ÿ^|•ÿ4Žßÿ!öÿ†üÿœþÿ ­þÿ ²þÿ ³þÿ!³þÿ²þÿ°þÿ³þÿ!¹þÿ"·þÿ$¼þÿ(Ãþÿ#ºÿÿ¥ùÿ&j°ÿ/9rÿ,9ÿ+4€ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿD"ÿJÿ«fÿ–g%ÿ”g&ÿ›j'ÿœl(ÿœm)ÿ p,ÿ¬|1ÿ´‚4ÿ®|4ÿ®{4ÿ­|4ÿ¬{6ÿ¯~8ÿµ‚;ÿ¶„<ÿ¶„=ÿ¹…=ÿ¾ˆAÿÃCÿÁDÿÇ‹@ÿߨLÿà«SÿÙ«]ÿéÌ|ÿïÄiÿØNÿÏ•JÿØ›Nÿã¥Rÿè¥Rÿõ¯Wÿû¾ZÿþäuÿÿÿÑÿÿúåÿþí°ÿüì¹ÿÿøÄÿöÙŽÿÛ¢PÿÌŒ?ÿÉ‹CÿÊ‘GÿÊ“IÿÉ’HÿÈHÿÈ‘GÿÆGÿÅŽEÿГAÿæ¦EÿùÒ|ÿÿþÐÿöáªÿÊ“Dÿ³|5ÿ¶„>ÿ¶‚;ÿ´‚;ÿ³‚;ÿ°~9ÿ«{6ÿ­~7ÿ¯6ÿ©x2ÿ¢r.ÿžo,ÿ¡s-ÿ¦v,ÿ q)ÿl&ÿ˜j(ÿ£gÿ®iÿ„v`ÿJ…¹ÿ&|Úÿ{íÿ˜ýÿ"¨ÿÿ¥þÿ©þÿ§þÿ§þÿ!³þÿ"´þÿ¯þÿ ªþÿ#¯þÿ%±þÿ ©ÿÿ˜ùÿ&e°ÿ.7pÿ//vÿ.(qÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ+ÿp:ÿ§^ ÿ¤l!ÿ—i'ÿ™i&ÿ™j(ÿm)ÿŸn+ÿ p-ÿ§w/ÿ¯~3ÿ¸‡:ÿ¸‰=ÿ±€8ÿ°}8ÿ±€9ÿµ‚:ÿ·…=ÿ¹†?ÿ»ˆ@ÿÂBÿÈFÿÆEÿÄDÿÉŽDÿÈ?ÿÅŠ>ÿÊ‘FÿÔšMÿÓ™LÿÑ–KÿÓ—LÿÕšMÿךMÿàŸPÿè¦RÿùÀ[ÿÿõŸÿÿÿÿÿÿÿþÿÿÿ÷ÿøà¢ÿÚšEÿËŠAÿΓKÿЖMÿΖKÿÍ”JÿÌ“JÿË“IÿÉ’GÿÉGÿÇGÿÉ‘HÿÏAÿá£Bÿúè¡ÿüóÃÿÚ¤Xÿ¹3ÿ¹†?ÿ¸ƒ=ÿµƒ;ÿµƒ;ÿ´€:ÿ®}6ÿ®}6ÿ¹‰<ÿ¹?ÿ­}6ÿ§t.ÿ¤s.ÿŸn,ÿšl(ÿ™j&ÿ˜i&ÿ”d#ÿ¥bÿ¢o3ÿitzÿ3m¬ÿ!}áÿšýÿ¢ÿÿŸþÿ¥þÿŸþÿ¡þÿ ±þÿ ¯þÿ¦þÿ þÿŸÿÿ”þÿŸÿÿ  ùÿ(a°ÿ2&mÿ3gÿ2]ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿO(ÿ˜Sÿ¨iÿ”g&ÿ—g&ÿœl(ÿžn*ÿ¥s-ÿ¨v/ÿ¤t.ÿ¡q.ÿ¨x3ÿº?ÿ»Ž@ÿ±8ÿ²8ÿµƒ;ÿ·„<ÿº†?ÿ¾‰@ÿÄŽBÿÆDÿÄDÿÃŒDÿÅEÿÅEÿÅŽHÿϘKÿÍ“HÿÌ‘IÿÏ•KÿÒ—LÿЖLÿÑ—LÿÕ™NÿךOÿßžPÿô³YÿÿîŸÿÿÿýÿÿÿûÿþî¸ÿè¬Nÿ΋AÿÏ—NÿÑ—NÿÑ—MÿÏ–LÿΕKÿΔKÿΔIÿÌ“JÿË’IÿË’IÿÊ’IÿÈŒBÿÕ›Cÿõá—ÿÿò·ÿç­[ÿÄ‹:ÿ¼‰Bÿº†?ÿ·„=ÿ·ƒ<ÿ´ƒ;ÿ°€8ÿ®{5ÿ´ƒ:ÿ¾“Dÿµˆ=ÿªv0ÿ©w0ÿ£r/ÿŸo*ÿœm'ÿ›j%ÿ”g'ÿ–`ÿªhÿŠiCÿLhˆÿ.…Öÿ  üÿ¥ÿÿ®þÿ#¸þÿ#¹þÿ"¸ÿÿ²þÿ«þÿ¬þÿ¯þÿ"´ÿÿ¢þÿ¬ÿÿ ¨ùÿ)_°ÿ3!kÿ1!kÿ0 eÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ/ÿw<ÿ©cÿj#ÿd%ÿ—h&ÿ›l(ÿŸn*ÿ¤s-ÿ¥t.ÿ¤t/ÿ¤t1ÿ©z5ÿ³ƒ:ÿ´‚:ÿ±9ÿµƒ;ÿ»ˆ>ÿ½‰@ÿ»‡Aÿ¿‰BÿÅŽDÿÅCÿÂŒCÿÂŒDÿÆFÿÇGÿÉIÿÔ›MÿÔ›NÿјMÿЗMÿÒ˜MÿÒ—LÿÓ˜NÿÖ›PÿלQÿßRÿò±XÿÿçšÿÿÿüÿÿùËÿôÇeÿÙ”BÿÑ–OÿÔ™PÿÔ™NÿÒ˜MÿÒ—NÿÒ™NÿÒ–MÿЕKÿΓKÿÍ”KÿΔJÿË“JÿÊŽCÿØ Kÿøæžÿþí¬ÿä§TÿÇ‹=ÿ¿ŠBÿ¿ŠAÿ»‡@ÿ¹„=ÿ¶…<ÿ´ƒ;ÿ°~8ÿ¬{6ÿ´„:ÿ´„9ÿ¨x2ÿ¤t/ÿ¢s.ÿ¤s,ÿ¡q*ÿšj'ÿ p*ÿr+ÿ§iÿ¡e"ÿklpÿ<‰Ëÿ%¡öÿ¨ÿÿ ¸ÿÿ)Ìÿÿ-Ñÿÿ)Êÿÿ!ºþÿ´ÿÿ¸ÿÿ!¸þÿ$¶þÿ!ªþÿ¬ÿÿžúÿ(]µÿ1$mÿ/(sÿ.*rÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿQ)ÿ›Uÿ©kÿ”g'ÿ˜i&ÿ›k'ÿ›l(ÿn+ÿŸq-ÿ¢s.ÿ¦v1ÿ¨x3ÿªz4ÿ¬{6ÿ¯|8ÿ³‚:ÿ¸†<ÿ¾‰?ÿ¿Š@ÿ¼ˆ@ÿ¾ˆAÿÁ‹CÿÃDÿÂCÿÄŽEÿÆGÿÇGÿË’IÿΕKÿÑ—MÿÒ˜MÿÒ˜MÿÓ˜NÿÔ˜NÿÕ˜OÿלQÿÚžRÿäŸRÿ÷µXÿÿíœÿÿÿûÿüæÿè£FÿÔ•PÿÖ›QÿÖšQÿÖ›PÿÖ™OÿÕšOÿÖ›PÿÕ™OÿÒ—MÿÑ•LÿÏ•LÿΕJÿÌ“JÿÊCÿÚŸLÿùå¢ÿþñªÿë¨IÿЈ2ÿÊ‘@ÿÍ•Gÿ¿ŒAÿ¸†>ÿº‡?ÿ¸†=ÿ´ƒ;ÿ®}8ÿ¬{6ÿ¯}5ÿ«{3ÿ£u/ÿ¡r-ÿ¢s-ÿ q,ÿ˜i'ÿ¢q*ÿ¤x.ÿœiÿªdÿuWÿPµÿ-›êÿ¤ýÿ!¹ÿÿ'Ëÿÿ(Ëÿÿ$Ãÿÿ ·þÿ!¹ÿÿ!¿ÿÿ ¸þÿ!´ÿÿ¦þÿ¡ÿÿ›úÿ(X«ÿ1 cÿ/"iÿ/!eÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ+ÿu=ÿ®jÿ¤p$ÿ™i(ÿ¡o)ÿl)ÿn*ÿ¤t.ÿ¥u/ÿ¨w0ÿªy4ÿ©y4ÿ«z4ÿ®}7ÿ°€9ÿµ„;ÿ»†=ÿ¼†?ÿ¼ˆ@ÿ¿‹AÿÁBÿÃŒCÿÃEÿÄEÿÆHÿÈGÿË’HÿΓJÿÏ”KÿЖMÿÒ—NÿÔ™NÿÖšPÿØ›PÿÙœQÿÞŸSÿä¤Vÿô¯YÿþÔoÿÿúÊÿÿùÛÿýÒhÿë¢QÿÙ›SÿÚœQÿÚœRÿÛRÿÚœQÿ×›QÿךPÿÖšPÿÔšOÿÔ˜OÿÒ—OÿΖMÿÌ”LÿËBÿÞ¥Pÿûê­ÿÿü¯ÿúÓhÿí¿iÿå·hÿÖžLÿ¿Š>ÿ¹†?ÿº†?ÿ·…=ÿ¶„;ÿ²€:ÿ®}6ÿ­|5ÿªy4ÿ¨x2ÿ«z2ÿ§w0ÿ p,ÿœl)ÿšj'ÿ™j'ÿd$ÿ§eÿ¦t8ÿj‡ÿ9‘Õÿ"˜öÿžüÿ¯þÿ"»þÿ³þÿ±þÿ ´þÿ"¾þÿ"¿þÿ"¾ÿÿ¯ÿÿ¦ÿÿšóÿ'I‡ÿ4Cÿ2[ÿ1WÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿH$ÿ‘Nÿ©iÿ›l(ÿ¢p*ÿ£q(ÿ™j(ÿŸp,ÿ«{2ÿ¯}3ÿ®|3ÿªz4ÿ©z5ÿ®|6ÿ±8ÿ³ƒ:ÿ¹†=ÿ¼ˆ@ÿ»‡@ÿ»ˆ@ÿ¾ŠBÿÃŽDÿÆEÿÇŽGÿÈHÿÇHÿΖKÿÕOÿÓ™MÿÒ–NÿÒ™NÿÓ˜OÿÖšQÿÙœQÿÜžRÿà¡Tÿç¥Vÿô­ZÿþÎqÿÿ÷¹ÿÿÿîÿÿëÿý¿Uÿñ«[ÿà¡TÿÞŸTÿà Sÿá¡TÿÜžTÿØœSÿØ›QÿØ›QÿÕšQÿÕ™OÿÔ™OÿјMÿÏ”KÿוCÿîÂsÿþúÔÿÿÿ×ÿÿúÒÿþ÷ÚÿõÙŽÿÔ•>ÿÀ…<ÿ¾‹Eÿº‡Aÿ·…>ÿ¶…;ÿ´ƒ;ÿ±€9ÿ­}6ÿ§w4ÿ©y2ÿ´‚6ÿ±~4ÿ¦t.ÿŸo*ÿ˜j(ÿ–f%ÿ–i(ÿœgÿ«lÿ…zeÿJŠ»ÿ(’ìÿƒóÿ•ûÿ¦þÿžþÿ¬þÿ ´þÿ ¸þÿ"¸þÿ"¹þÿ°ÿÿ¦ÿÿ†ßÿ':tÿ7 Aÿ2%jÿ.+mÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ#ÿh4ÿ¦\ ÿ¢j ÿ•h(ÿ n)ÿŸn(ÿ›k)ÿ¡s-ÿ©x1ÿ­{3ÿ­{3ÿªy4ÿ­|5ÿ³€8ÿ´‚9ÿ´ƒ;ÿ¹…?ÿ¼‡@ÿ½‰@ÿ¿‹AÿÃŒCÿÆEÿÇ‘GÿÇ‘GÿÉGÿÍ“JÿÙ QÿÜ£RÿÔ›NÿÓ˜NÿÕ™PÿÕšQÿØœQÿÛŸTÿß Tÿæ¦VÿðªYÿû³\ÿÿ߇ÿÿÿõÿÿÿòÿÿì‘ÿû¹Uÿî¦Zÿå¤Xÿä¤Wÿä¤Vÿâ¤VÿÞ¡TÿÛSÿÚžRÿÚSÿÙ›QÿךPÿÕšPÿÒ˜NÿÓ”Gÿæ¦Oÿüä°ÿÿÿþÿÿÿýÿÿÿóÿÿÿþÿùéµÿà§Bÿʆ1ÿ¿†@ÿ¹…?ÿ¹…>ÿ·„=ÿ³;ÿ¯~8ÿ®}9ÿ«{6ÿ¨x2ÿ«|3ÿ­|3ÿ¬y1ÿ£s,ÿ™k(ÿ˜h'ÿ£q)ÿ˜i%ÿ§eÿxDÿa‰Ÿÿ1‘ßÿõÿ Ÿýÿ ¡þÿ’þÿ þÿ±þÿ³þÿ¥þÿ!£þÿ˜øÿ‹ëÿtÓÿ&E’ÿ2,gÿ-?~ÿ+?~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ8ÿ„Cÿ®iÿ¡o)ÿm)ÿm(ÿ™k)ÿn,ÿ¤t/ÿ§w0ÿ§v1ÿ¨w2ÿ«{5ÿ´‚9ÿ¹„<ÿµƒ;ÿµ‚<ÿ¹…?ÿ¼‡@ÿ½‰@ÿÄŽDÿË“GÿÉ‘GÿÆGÿÇ‘GÿÉHÿÒ–LÿÖœPÿÕšOÿÔ—OÿÔ™OÿÖšPÿØ›QÿÛRÿÞ Uÿá¡Wÿè¨Yÿò¬[ÿú¸_ÿÿâƒÿÿþòÿÿþòÿÿñ™ÿü¾Zÿó©\ÿé©Zÿæ¦Xÿä¥Xÿâ£Vÿá¢UÿÞ UÿÝŸUÿÛSÿÜžRÿÛœRÿÙœQÿÖ™Pÿ×–Fÿí¹fÿÿ÷Éÿÿÿèÿÿÿ¿ÿÿÿ¦ÿÿÿÕÿþüùÿøãªÿå¯Qÿ΋3ÿÄ4ÿ¾‚6ÿ¼5ÿ¿ƒ3ÿ¿ƒ1ÿ½‚4ÿºƒ9ÿ®|7ÿ¥v3ÿ§w1ÿ«y1ÿ¥t.ÿ›l*ÿ›l)ÿ¥t*ÿžo*ÿ¥gÿ«s)ÿw…€ÿ?‹Íÿ#’ñÿ!¢ýÿ"¨þÿšþÿžþÿªþÿ °ÿÿ›ýÿŽøÿ‚êÿxßÿ~åÿ&b°ÿ-Cxÿ,Kÿ+H~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿQ(ÿ˜Qÿ¦iÿ—j)ÿžm'ÿŸn(ÿ›m*ÿžo,ÿ¢r/ÿ¥u/ÿ¦w1ÿ§x3ÿ¬}6ÿ¶ƒ:ÿ¹„;ÿµ„;ÿ¶ƒ>ÿº†@ÿ½‰AÿÀŠBÿÅFÿÈ’GÿÇGÿÈHÿÊ’IÿÌ“IÿЕKÿÏ•LÿÒ–NÿÖ™Oÿ×›QÿלRÿÛŸRÿÝŸTÿß Vÿã¢Wÿå¦Xÿì¨Zÿû·aÿÿÝwÿÿþÎÿÿþïÿÿì‚ÿÿÁdÿü¶cÿð­]ÿç¥Yÿä¤Xÿã¤Wÿâ¢Xÿá¢Wÿà UÿßžTÿÝŸUÿÞ UÿÞ TÿÚ›PÿÝšJÿòÆ~ÿÿü¿ÿÿò•ÿÿèkÿÿéoÿÿ÷ŽÿÿÿÌÿÿÿêÿüòÉÿñÔŒÿéÄlÿà°YÿÛ¤Lÿç·ZÿëÁ`ÿå°KÿÛœ:ÿĆ6ÿ°y2ÿ¨v.ÿ¤s.ÿžo,ÿ˜i*ÿ˜i*ÿ¥x.ÿ¡s-ÿ˜eÿªgÿ‹bÿN‹¸ÿ%…Þÿ÷ÿ›ýÿþÿþÿ ¨þÿ ¨ÿÿ•ûÿôÿ‘ôÿ‡òÿ—øÿ'wµÿ.Brÿ,Jÿ*L}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ$ÿj6ÿ¢\ ÿg!ÿ”i'ÿžl(ÿžm)ÿ›m)ÿ q-ÿ¦u0ÿ¦v0ÿ§w3ÿªz5ÿ±€8ÿºˆ=ÿ¸†<ÿ¶ƒ<ÿ¸…>ÿ¼‰@ÿÀ‹BÿÂŒBÿÄEÿÅFÿÇGÿË’HÿÍ”IÿÏ–LÿЖLÿÒ—MÿÔ™NÿÖ›PÿÙPÿÜžTÿß¡UÿÞ Uÿà¡Vÿã£Wÿã¤Yÿê¦Zÿõ¯_ÿüÈhÿÿ÷¤ÿÿÿóÿÿðÿÿÆ_ÿý°bÿó®_ÿé¦Zÿç¥Yÿå¦Zÿä£Yÿä¤Wÿâ¢Vÿá¢Vÿà Vÿâ¢Vÿã¤XÿàžRÿç£OÿùÖ“ÿÿþÇÿþØzÿü¸Nÿø»\ÿùÉ`ÿúÐfÿù׋ÿýðÂÿÿÿÕÿÿÿÌÿýö·ÿüñµÿþùÓÿÿúãÿýò½ÿùÑlÿà¢;ÿÌ‹3ÿLJ.ÿ¸z(ÿ«p$ÿ£jÿœfÿ n!ÿœl%ÿa$ÿ¡aÿœyDÿb¡ÿ/„Õÿ†óÿýÿ’ýÿ•þÿ ¦þÿ ¢þÿ›üÿ §ûÿªþÿ¬þÿ!°úÿ*{±ÿ-Fqÿ*Pÿ(P}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ ÿ6ÿBÿ¦dÿ—h$ÿ™k'ÿ§s*ÿ¤r+ÿo+ÿ¡r.ÿ¨x1ÿªy2ÿ©y3ÿ«z5ÿ´‚:ÿÄ’BÿÁAÿ¸„=ÿ»†>ÿ¿‰@ÿÁ‹BÿÃCÿÅŽCÿÇGÿÊHÿÍ“HÿΕJÿÑ—LÿÓ™MÿÖšOÿלPÿØœQÿÛžRÿß Tÿß¡Uÿà¡Vÿá¢Wÿä¤Yÿè¦[ÿê§[ÿî©]ÿö²^ÿÿÚxÿÿüÎÿÿûÞÿÿØoÿý²`ÿó¬_ÿë©]ÿê¨\ÿè§[ÿç¦Yÿæ¥Xÿå¤Yÿå¥Yÿå¥Xÿæ¥Xÿå¤Xÿå¡Rÿñ¯Sÿÿç§ÿÿþÛÿþÒ}ÿô§Jÿè¢SÿßOÿÜ™GÿÛšCÿá«WÿíÂwÿöÕŠÿýä”ÿýè¢ÿûì±ÿÿøËÿÿÿíÿÿýÖÿùè‘ÿóÝÿôÖƒÿë¾mÿã´\ÿÛ«MÿÌ—;ÿº„+ÿ©s!ÿ’`ÿ—\ÿ¥o,ÿt‡†ÿ;ŒÊÿ ðÿ”ýÿ•ýÿ‘üÿšýÿ!œÿÿ"¢þÿ!¬ÿÿ£þÿ!ºÿÿ$¼ùÿ+z°ÿ-Jqÿ(Xÿ(V}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ ÿG#ÿLÿ¨iÿšl(ÿl(ÿ§t+ÿ¥s,ÿ p-ÿ£s/ÿ§w2ÿ¨w3ÿ¬z6ÿ­|6ÿ²€8ÿÁŽ@ÿÅBÿ¼†?ÿ»†>ÿ¿Š@ÿÂŒBÿÅDÿÇEÿÊ’GÿË’IÿÍ“JÿΗKÿÒ˜KÿÕ™NÿךPÿÚœQÿÛŸRÿÜ TÿÞ¡Tÿà¢Vÿã¤Wÿä¥Xÿç§Zÿë©[ÿë¨[ÿìª\ÿñª]ÿý½aÿÿì˜ÿÿÿúÿÿó¹ÿþËmÿô«^ÿî«]ÿí«^ÿê©\ÿé¨[ÿè¦[ÿé¨[ÿìª\ÿì©[ÿé©[ÿæ¦Yÿè¢Tÿó±SÿþäŸÿÿÿàÿþÚˆÿóªJÿßœQÿДLÿÌ‘IÿÊŽDÿÌ?ÿÓ’=ÿÛAÿá£HÿÜ£KÿØŸFÿä°Nÿ÷؃ÿþõ½ÿþ÷²ÿÿ÷ªÿÿûÅÿÿú¼ÿÿü¶ÿþ÷ÈÿùëËÿñÞ¤ÿܹdÿ´ˆ:ÿj"ÿ©hÿxhÿE†¶ÿ#…ÝÿŽôÿ!˜ýÿ“ýÿ’ýÿ ˜ýÿ ¡þÿ£þÿ§þÿ!¹ÿÿ#¾ùÿ*z°ÿ1Aqÿ+Pÿ)S}ÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿY-ÿ›Sÿ¤iÿšk)ÿœl'ÿ¢q*ÿŸp+ÿŸp-ÿ¤t/ÿ§w2ÿ«y3ÿ­|5ÿ¯~7ÿ±€8ÿ¸„<ÿ¿‰>ÿ¾ˆ?ÿ½ˆ?ÿÁŒAÿÃŽBÿÇ‘EÿË”GÿÌ”IÿÍ”IÿÏ•JÿЗKÿÓ™LÿÖ›MÿØOÿÙžQÿÜ¡RÿÞ¡Tÿà¢Vÿâ¤Wÿç§Xÿè¨Yÿê©Zÿë©[ÿíª[ÿîª\ÿñ«]ÿú³^ÿÿÖ~ÿÿÿìÿÿýàÿÿ×hÿú«^ÿõ¬aÿð­`ÿì«^ÿë©]ÿê¨\ÿì©\ÿî«]ÿì«]ÿëª\ÿì©Zÿî©Zÿõ­UÿþÎsÿÿûÉÿýç´ÿë«VÿÖ•HÿЗNÿΔLÿË’IÿÊ’HÿÏ•IÿÕ™IÿÐ’DÿÇ?ÿÁ†;ÿŇ7ÿÒ˜<ÿÔ¥OÿТTÿÓ¢Uÿá³eÿæ¾eÿëÇmÿúè¥ÿÿÿÃÿþø¯ÿðß•ÿÚÂ~ÿ³‹Gÿ¬jÿuQÿR‚¨ÿ'{Çÿ‡èÿ!˜þÿ’úÿ”üÿ˜ýÿ¢þÿ¤þÿ¬þÿ°ÿÿ°ùÿ't°ÿ3Ngÿÿÿÿÿÿÿÿÿÿÿÿ$ÿj7ÿ¥_ ÿh"ÿ“g'ÿ›l(ÿžn)ÿœn+ÿŸp-ÿ£r/ÿ®}5ÿ¹‰;ÿ´ƒ8ÿ®}6ÿ³7ÿ¸„:ÿ¼‡=ÿ½‰>ÿÀ‹?ÿÂ@ÿÅŽCÿÊ’EÿÍ–HÿÏ—HÿЗHÿИIÿÓ˜LÿÖ›NÿØOÿÚžPÿÛ QÿÞ¡Tÿâ£Uÿä¤Vÿå§Wÿè¨Xÿê©Zÿêª[ÿëª\ÿï«]ÿð¬^ÿó¯_ÿú²`ÿÿÉoÿÿúÉÿÿýïÿÿÞrÿÿ¶Rÿü®_ÿö­cÿð­`ÿî«_ÿíª^ÿìª\ÿí©\ÿî«]ÿð­]ÿó¯^ÿö¯_ÿû³YÿÿÏhÿÿû»ÿøèÆÿá©^ÿÓ’AÿÒ™OÿЖLÿΔJÿÍ”JÿÓ˜LÿלLÿÏ–HÿÇDÿÂŒBÿ¼‡Aÿ¹‚;ÿ¶~3ÿ±y/ÿ²y/ÿÀ…1ÿˆ1ÿ¹,ÿË—<ÿä·Lÿ׫FÿÀšKÿÀœSÿª;ÿ¥gÿœxCÿb–ÿ,s¸ÿ€Ûÿ•øÿ “úÿ•ûÿ”ýÿ þÿ"³ÿÿ ®þÿ¥ÿÿùÿ&r°ÿ.Hqÿ*Tÿ)U}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ.ÿ{Cÿ±sÿŸp)ÿ˜j(ÿ¦u+ÿ¡r,ÿn*ÿ p-ÿ¤r.ÿ²‚6ÿ—Cÿ¼Ž?ÿ±~7ÿ´8ÿ¹†<ÿ¼ˆ>ÿ¿‰?ÿÁ‹@ÿÃ@ÿÆCÿÉ“EÿË•FÿΖHÿИHÿјKÿÕšMÿÚžNÿÜžPÿÜŸPÿÝ¡Rÿá¤Uÿä¦Vÿæ§Wÿç¨Xÿê©Yÿíª[ÿí«\ÿí¬\ÿï¬^ÿò¯_ÿö±aÿû³bÿÿÆhÿÿì™ÿÿÿíÿÿöÕÿÿà…ÿÿÇ_ÿý±Zÿö­cÿï­aÿî«^ÿíª^ÿïª]ÿö®_ÿú´aÿù·cÿü´`ÿÿ¾^ÿÿèŒÿÿÿáÿøçËÿâ«[ÿÖ”BÿÔšQÿЖLÿÍ”KÿË“IÿÍ”IÿÏ“JÿË‘GÿÅDÿ¿‹Aÿ»‡@ÿ¸„>ÿµ‚;ÿ³€9ÿ¯|6ÿµƒ9ÿ¿‘Bÿ³ƒ8ÿ¨s)ÿ°w(ÿ¨r$ÿšg!ÿ¦v+ÿžq,ÿaÿ£u6ÿn‚‰ÿ1l­ÿ|ÚÿŒðÿ‘÷ÿ’ùÿ‹øÿ–ýÿ!°ÿÿ$¸þÿ«ÿÿœùÿ%v°ÿ+Qqÿ+Xÿ,R}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿ:ÿ‰Kÿ¸{#ÿ¢w.ÿšj'ÿªu,ÿ¥t,ÿžo+ÿ£s.ÿ§v0ÿ´‚6ÿÁ‘?ÿÁ‘?ÿ·„9ÿ¶‚9ÿ»‡<ÿ½‰=ÿ¿Š>ÿÂ@ÿÈ’CÿÌ•FÿÊ•EÿË•EÿÏ—GÿÑ—IÿÓšJÿØMÿÜ NÿÜ OÿÝ QÿߢRÿã¥Sÿå§Tÿæ¨Wÿè©YÿìªZÿï­\ÿï­]ÿï­]ÿð®]ÿò¯_ÿö°`ÿü´cÿþ¼fÿÿÒsÿÿô§ÿÿÿéÿÿþèÿÿñ±ÿÿÎhÿý­Pÿöª_ÿð¬bÿð­_ÿô¯aÿý´dÿÿ¹fÿþ¶dÿþ±]ÿÿÊZÿÿö˜ÿÿÿøÿüóìÿè¼ÿÔ’:ÿÑ’GÿÑ—OÿÏ•LÿÌ“JÿÉ‘HÿÇFÿÆFÿÆŽEÿÁ‹Cÿ¼‡?ÿ¸…=ÿ·„<ÿ¶„<ÿ°~8ÿ²9ÿ½?ÿºŠ<ÿ©x2ÿžn,ÿ˜j)ÿši(ÿ¬4ÿ£v.ÿ›dÿ©s+ÿz‡ÿ:z¸ÿ ˆêÿ‹ðÿ‡éÿöÿŠôÿ‹ùÿ™üÿ#°þÿ©ÿÿ ùÿ&s°ÿ.Mqÿ-Vÿ,Q}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿG$ÿ”Qÿ²tÿ›n(ÿ–f'ÿ¦r*ÿ¥s+ÿŸo,ÿ¦u/ÿ¬z2ÿ²5ÿ»ˆ:ÿ¿Œ;ÿº†:ÿ¸…9ÿ¾Š<ÿÂ>ÿÂ>ÿÂ@ÿÍ–EÿÒ™FÿÍ–EÿÍ—EÿÑ™HÿÓšJÿÕKÿÙ LÿÜ¢NÿÝ¢OÿߣPÿà¤Qÿä¦Sÿç©VÿêªWÿë«Yÿí¬Zÿî­[ÿð®]ÿñ¯]ÿñ°^ÿó°`ÿö±`ÿû´cÿÿ·gÿÿÂjÿÿ×rÿÿéÿÿöÆÿÿÿóÿÿóÑÿÿÏyÿý²Tÿú¬^ÿø°eÿú²cÿÿ¸fÿÿ¾mÿÿ¼cÿÿÆYÿÿéÿÿýËÿÿÿûÿþþÿÿóÞËÿߨeÿÑ<ÿÎ’JÿÌ”MÿË“IÿÊ‘IÿÆGÿÆFÿÇDÿÁŒBÿ»ˆ?ÿ»‡?ÿ»ˆ>ÿ·…;ÿ±9ÿ°~7ÿ²6ÿ°~5ÿ©y1ÿ¡s-ÿšm*ÿžn*ÿªz/ÿœn*ÿ˜gÿ°r"ÿ‚}nÿC‰Äÿ$Žñÿ÷ÿˆìÿŒòÿôÿûÿ—ýÿ£þÿ¥ÿÿ¦ùÿ'q°ÿ-Iqÿ)[€ÿ'Y~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿQ)ÿ›Yÿ®sÿn*ÿ¢p)ÿ©v*ÿ¨u-ÿ¥t.ÿ¨v.ÿ­z1ÿ®|3ÿ´6ÿ¸…8ÿ·…8ÿ¹‡9ÿÀŒ;ÿÅ>ÿÄ?ÿÅ‘@ÿÌ–CÿϘDÿΗDÿИEÿÔœHÿÖžIÿØŸIÿÙŸKÿÛ¢MÿÞ£Nÿá¤Oÿã¦Qÿå©Sÿé«Vÿì¬Wÿî­Xÿî¯Zÿï®\ÿð¯\ÿò¯]ÿô±_ÿô²`ÿõ²aÿü¶cÿÿ»gÿÿ¿jÿÿÀiÿÿÆgÿÿÒvÿÿë«ÿÿÿäÿÿùÜÿÿÝÿÿ¾Sÿþ²Wÿÿ³`ÿÿ¹bÿÿÊdÿÿßkÿÿñ˜ÿÿþâÿÿÿóÿÿü½ÿÿù©ÿüüÌÿóåËÿå½zÿ×™Aÿ΋GÿÉ‹IÿÈGÿÇGÿÆEÿÃDÿÀŠBÿ½‰Aÿ¿ŠAÿ¾Š?ÿ·„;ÿ²8ÿ²8ÿ¯|6ÿ©x3ÿ¥v0ÿ¢s.ÿ¢q,ÿ¢r,ÿ n(ÿ˜g&ÿœk#ÿ¶uÿ‹|bÿI{­ÿ&†ãÿ”úÿ÷ÿ‘÷ÿùÿ”þÿ¡þÿ¢þÿ«ÿÿ «ùÿ&u°ÿ+Lqÿ*Vÿ)S}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿZ,ÿ¡` ÿ´{$ÿ«z/ÿ­w+ÿ¦s*ÿ¥t,ÿ¦u-ÿ¨v/ÿ­z0ÿ¯}2ÿ±~4ÿµƒ6ÿº‡8ÿ½‰;ÿÀ=ÿÄ>ÿÆ?ÿÉ“@ÿË•AÿÍ–BÿΘBÿÑ›DÿÔFÿןHÿÙ¡IÿÚ¡JÿݤLÿߥLÿá¦Oÿå©Qÿç«Rÿê¬Sÿí®Uÿî¯Xÿð°Yÿò±\ÿñ±[ÿô°]ÿõ±^ÿ÷²`ÿö³`ÿûµbÿþ¹fÿÿ»hÿÿ¼hÿÿ½iÿÿ¿fÿÿÇkÿÿ݈ÿÿöÅÿÿýêÿÿê¯ÿÿÚuÿÿÚpÿÿÙoÿÿæ{ÿÿü¶ÿÿÿøÿÿÿûÿÿû¼ÿÿÞqÿÿÓdÿÿç…ÿÿûÔÿúóßÿòÍtÿë±Bÿá§OÿÍ”LÿÄŒFÿÅŽFÿÃŒDÿ¿ŠBÿ½‰AÿÀŒAÿ½‰?ÿµ:ÿ³‚:ÿ²9ÿ®}6ÿ¨y3ÿ¥u1ÿ£s/ÿ¦s.ÿ£q,ÿ›l(ÿ—f$ÿ¡q'ÿ¹‚/ÿ•…bÿNw›ÿ&ƒØÿ‘úÿ•ýÿ˜ÿÿ™ÿÿ“ýÿ•üÿ¤þÿ!´ÿÿ!¯ùÿ&{°ÿ*Oqÿ+Rÿ*M}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿ]/ÿ¥c ÿµ}&ÿ¦s-ÿ¡m'ÿ o(ÿ p*ÿ£s,ÿ¦u.ÿ«z0ÿ¯~2ÿ²€5ÿ·„8ÿ¼‰8ÿ¾‹:ÿÁŒ;ÿÅ=ÿÆ’?ÿÉ”?ÿË–?ÿΙAÿÑ›CÿÔœDÿÖžDÿØ GÿÛ¢HÿݤHÿà¥Kÿá§Mÿã©NÿåªOÿç¬Rÿë¯Tÿí¯Vÿï°Wÿð²Xÿò²Zÿó³[ÿô³\ÿö²^ÿø³_ÿøµaÿù¶aÿý·eÿþ¸eÿÿ»gÿÿ½iÿÿ»hÿÿ·eÿÿ¼bÿÿÖ{ÿÿùÅÿÿÿöÿÿûçÿÿûÏÿÿúÌÿÿüàÿÿÿùÿÿÿáÿÿñ¦ÿÿÕuÿÿ½^ÿÿº`ÿÿÏfÿÿïÿÿÿãÿÿùßÿýð”ÿùÖdÿä¥PÿÌGÿÅŽGÿÃŒEÿÁŠBÿ½ˆAÿ‹BÿÉ”EÿÀŒAÿ´ƒ<ÿ²8ÿ­{5ÿ¨x2ÿ¦v1ÿ¡r.ÿ©{0ÿ¨z.ÿn)ÿ•d$ÿ›k&ÿ·+ÿ™UÿT|˜ÿ+ŒÞÿ—ýÿšþÿ þÿ ¥þÿœþÿ›ýÿ þÿ ­ÿÿ!­ùÿ'v°ÿ*Iqÿ(Vÿ'V}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿc4ÿ§f ÿ­x%ÿœk)ÿœk'ÿm(ÿ£r)ÿªx-ÿ©x.ÿ«y/ÿ±~3ÿ¼‡8ÿÁ:ÿ¾‹8ÿ¾‹8ÿÂŽ:ÿÆ’=ÿÉ•>ÿÉ–>ÿÌ™?ÿÒAÿÔžBÿÕžCÿØ CÿÚ£EÿܦHÿà§Jÿâ¨Kÿã«Lÿå«Mÿç¬Oÿë°Qÿí°Sÿî°Uÿï²Vÿò³Wÿò³Yÿõ´Zÿõ´\ÿöµ^ÿø¶_ÿù¶aÿú·bÿü¸bÿþ¸eÿÿºfÿÿºgÿÿ·fÿþ¶fÿþ¶fÿþÁiÿÿÙ|ÿÿôªÿÿÿ×ÿÿÿ÷ÿÿÿüÿÿýÚÿÿî«ÿÿÜÿýÄeÿ÷°\ÿó©[ÿô°_ÿþÌkÿÿäpÿÿ÷™ÿÿÿéÿÿÿñÿþë™ÿï®MÿÕ“EÿÈGÿÄEÿÁŒBÿ½ˆAÿÀŠBÿÆ’DÿÀ@ÿ³€9ÿ¶„;ÿ¹‹=ÿ°7ÿ©w1ÿ¢o,ÿ¬2ÿ®‚3ÿœm*ÿœl'ÿžl'ÿ¬nÿ—xGÿYÿ/ãÿ ’ýÿ•üÿ ¥ýÿ§þÿ¦þÿ"¥þÿ þÿ¤ÿÿ¦ùÿ'k°ÿ.>qÿ,L€ÿ*L~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿf4ÿªiÿ°€3ÿ¢r*ÿ¢m$ÿ n(ÿª{/ÿ±ƒ3ÿªz.ÿªy/ÿ²€3ÿ¿Œ8ÿÃ:ÿÀ8ÿÀ8ÿÅ’:ÿË—=ÿ͘=ÿÍ™=ÿМ>ÿÔž@ÿÖ BÿØ¢CÿÙ¤CÿܦFÿà©HÿâªIÿäªJÿå«Jÿæ­Mÿè¯Nÿí³Pÿî²Rÿî³Tÿð³Uÿñ´VÿóµXÿô·Zÿõ¶[ÿ÷·]ÿø·^ÿú·`ÿú¸aÿý¸bÿÿ¹dÿÿºeÿÿºfÿÿ·fÿý¶fÿý¶fÿÿºhÿÿÃhÿÿÚuÿÿû•ÿÿÿ»ÿÿý»ÿÿñÿÿÓmÿþ¸_ÿõ¬]ÿë§[ÿç¤Xÿê§Yÿø¹dÿÿËiÿÿØjÿÿð¢ÿÿÿúÿÿôÑÿî»\ÿÑ>ÿÇŽGÿÅEÿÁ‹Cÿ¾‰Aÿ¾‹@ÿ¼‰?ÿ·…<ÿ±8ÿµƒ:ÿ¼Œ>ÿ³‚8ÿ§w0ÿ p-ÿª{1ÿ¬~1ÿn*ÿ›k'ÿšj%ÿ¥gÿ—yHÿ[†¥ÿ/‡âÿŒüÿ™þÿ ¥þÿ¢þÿ!­þÿ"«þÿ"ªþÿ «ÿÿ ¦ùÿ(m°ÿ.:rÿ.?‚ÿ-9~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿf4ÿ«jÿµ…7ÿ¤r*ÿžk#ÿª|.ÿ»‘;ÿ¶Š8ÿªy-ÿ¬z.ÿ³1ÿºˆ4ÿ½‹6ÿ¿7ÿ‘8ÿÇ–9ÿÍ™;ÿΚ<ÿΜ<ÿÒž>ÿÕŸ?ÿ×¢?ÿÚ£AÿݦBÿáªEÿã­Gÿã­Gÿä­Gÿå®Jÿç°Mÿê²Mÿì´Oÿí³QÿðµRÿð´SÿòµVÿó·Wÿô·Yÿö¸Zÿø¸\ÿø¸^ÿú¸^ÿû¹`ÿü¹bÿþ¹dÿþ¹eÿÿºfÿþ¹eÿý·eÿþ·eÿþ¸fÿÿ½jÿÿÏrÿÿð†ÿÿÿ™ÿÿúÿÿßwÿþÁgÿ÷®_ÿë§[ÿä¤Xÿá¢Vÿä¤Wÿï¬\ÿú´`ÿû¸Yÿþ×mÿÿþÐÿÿüìÿñËwÿÑ‘:ÿÆ‹DÿÄFÿÁŒCÿ¾‰Aÿ¼‰@ÿ·…>ÿ³‚;ÿ²€9ÿ°~7ÿ±7ÿ­|4ÿ§w1ÿ q-ÿ©z1ÿ²‚2ÿ¥u+ÿ™i%ÿ“f#ÿ¢fÿšvIÿ^Œ§ÿ.‹äÿŽüÿœÿÿ!¨þÿ£þÿ§þÿ"©þÿ!«þÿ ¬ÿÿ$®ùÿ*s²ÿ.2nÿ2(qÿ2"kÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ!ÿg5ÿ©gÿ¬y*ÿ™i'ÿ›i#ÿ©y+ÿ³ƒ1ÿ°0ÿ­z-ÿ¯}/ÿ´‚0ÿ¸†2ÿ¼Š4ÿÁ5ÿÑ6ÿÇ•8ÿÌ™:ÿÏ›;ÿО<ÿÔ <ÿ×¢>ÿÙ¤@ÿÛ§AÿÞ©Aÿá­Cÿä¯Eÿä°Gÿä±Hÿæ²Iÿé³Iÿì´Kÿí¶MÿïµPÿð¶Qÿñ¸Rÿò·Uÿô¸Vÿõ¹Xÿö¹Yÿø¹[ÿø¹]ÿúº^ÿû¹`ÿü¹aÿýºcÿþ¹dÿþ¸dÿþ¹eÿþ¸eÿþ¸fÿþ·eÿþ»fÿþÆmÿÿÒuÿÿã|ÿÿèÿÿÖvÿüºgÿñª\ÿç¥Yÿä£Xÿá¡Wÿá¢Vÿå¦Xÿè¥Wÿì¦NÿúËkÿÿüÔÿÿÿéÿ÷ÕwÿÚš?ÿÇŒEÿÂŽEÿÁŒCÿ½ˆ@ÿ»‡?ÿ¾‹@ÿ»‰>ÿ³:ÿ®}7ÿ­|5ÿ«y3ÿ¦v1ÿ¡r.ÿ¦w/ÿªx.ÿ¡p*ÿ™i&ÿ‘c#ÿ dÿ™vJÿ_’¨ÿ0Ÿçÿ”þÿœÿÿ©þÿ!ªþÿ#±þÿ#®þÿ §þÿ«ÿÿ#ªùÿ'k°ÿ-5oÿ/0sÿ/*mÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿe3ÿ¨a ÿ©q"ÿ—h&ÿœj%ÿ¡p(ÿ¥t)ÿ©w+ÿ«y-ÿ°}.ÿ¶„0ÿ»‰2ÿ¿Œ4ÿÂ4ÿÅ’5ÿÈ–7ÿÌ›9ÿÑž9ÿÕ¢;ÿפ<ÿÚ¥<ÿܨ>ÿݪ>ÿ߬Aÿã±Bÿå²Cÿæ±Cÿç³FÿéµHÿëµIÿíµKÿî¸Lÿï¹Oÿñ¸PÿòºQÿóºUÿôºUÿõºWÿöºXÿ÷»Yÿùº[ÿùº]ÿûº_ÿüº`ÿüº`ÿüºbÿü¹cÿý¹cÿý¸dÿý¸eÿþ¸eÿý¶eÿý¸fÿþ¹fÿÿÁkÿÿÏqÿÿÆmÿù²bÿí©[ÿç¥Yÿä£Wÿà¢Vÿà¡Uÿá¢Uÿà TÿãžKÿôÀlÿÿúÒÿÿùËÿøÃ_ÿÛ–BÿÆGÿÂŽDÿÁŒCÿ¾‰Aÿ½‡AÿÄCÿ¿?ÿ³‚:ÿ¯}7ÿ¬{5ÿ©y3ÿ¦v1ÿ¢s/ÿ r-ÿžo+ÿšj(ÿ˜i&ÿ‘d#ÿ¡dÿ—vKÿ]“ªÿ0©èÿ¡þÿªÿÿ¬þÿ¨þÿ ©þÿ"¯þÿ!¬þÿ¥ÿÿ¢ùÿ'a¯ÿ/.qÿ+?~ÿ)B}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿa1ÿ¢Z ÿ¦kÿ˜j&ÿl%ÿ¢p'ÿ¥s)ÿªw,ÿ±~/ÿ¸„/ÿ¸†/ÿ»Š1ÿÂ3ÿÇ”5ÿÉ—7ÿÌš7ÿÑž7ÿÕ¡9ÿ×¥:ÿÙ§;ÿܨ<ÿ߬<ÿá¯>ÿã±Aÿæ³Bÿç´Bÿè¶Dÿê¸FÿìºGÿíºIÿî»Jÿï»Mÿð¼Mÿñ¼Oÿò»Pÿó¹Mÿô¹Jÿõ¸Nÿö¹Uÿø»Xÿû½[ÿú¼\ÿúº]ÿûº^ÿüº_ÿü¹aÿû¹aÿû¸bÿû·bÿü·dÿû¶dÿù³aÿ÷±`ÿö¯`ÿø³dÿü¹dÿù´bÿñ­_ÿì©\ÿç¦Zÿâ¢Wÿß¡VÿÞŸUÿÞŸTÿߟTÿä JÿõÁcÿÿúËÿÿôÉÿîµYÿÏŽ>ÿÅŽHÿÅŽFÿÂŒBÿ¾Š@ÿ¼‡@ÿ»…>ÿ¸…=ÿ´‚;ÿ¯~7ÿ«{5ÿ§w3ÿ¦v2ÿ¥u/ÿ p-ÿœn+ÿ›k(ÿ˜h'ÿb"ÿ¢eÿ–~Oÿ[–­ÿ.¡éÿ–ûÿ¦þÿ"·þÿ!°þÿœþÿ£þÿ"³þÿ¯ÿÿ ¡ùÿ&g°ÿ.6rÿ.;|ÿ-9zÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿZ-ÿŸY ÿ¬oÿŸo&ÿ£p&ÿ¥r&ÿ§t(ÿ¬y*ÿ·„-ÿ»‡/ÿ¹‡/ÿ½‹0ÿÄ’2ÿÊ—5ÿΛ7ÿÑž7ÿÒ£6ÿצ8ÿÚ¨:ÿݬ;ÿà®=ÿá°>ÿä²?ÿæ´@ÿç·@ÿè¹Cÿë»Eÿì¼Eÿí½Fÿî½Gÿï½Jÿð¾Kÿñ¾Mÿò¼LÿóÁOÿ÷Ì^ÿüä›ÿüã›ÿúÅZÿüÃSÿÿÍ_ÿü¿]ÿù»[ÿú»]ÿúº^ÿû¹_ÿû¸`ÿû·`ÿú·aÿú¶bÿø´bÿõ²`ÿó°`ÿò¯_ÿò®_ÿð­^ÿðª]ÿí©\ÿê©\ÿç¦Zÿâ£Vÿâ¤Vÿã¥Wÿß¡UÿÞPÿé¦LÿûÚÿÿÿêÿþé¨ÿêªKÿÎDÿÆHÿÉ‘GÿÄDÿ¼ˆ@ÿº†?ÿ¼†?ÿº…=ÿ³‚:ÿ­~6ÿªz4ÿ¦w2ÿ¨w2ÿ©x1ÿ¢s-ÿœm)ÿ˜i&ÿ›k(ÿ›j&ÿ¬jÿ–ˆWÿW›²ÿ)‘éÿýÿ—ÿÿ"´þÿ&Àÿÿ¯þÿ"³þÿ%·þÿ ±ÿÿ!©ùÿ(n°ÿ,;rÿ.=|ÿ.7yÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿR)ÿ\ÿ·~!ÿ¯„5ÿ¬|/ÿ§r&ÿªw(ÿ¯}*ÿµ,ÿ·„,ÿ¼‰.ÿÁ0ÿÅ”1ÿʘ3ÿÐ5ÿÔ¢6ÿÖ¦6ÿب7ÿÞ¬:ÿæ¶?ÿæ·@ÿäµ<ÿåµ=ÿè·>ÿéºAÿé¼Bÿì¾Bÿî¿EÿïÀGÿðÀHÿðÁIÿñÁJÿòÁLÿò¾KÿõÉQÿùÛgÿþé†ÿþñ’ÿÿóÿÿížÿÿè‚ÿûÂXÿø»Yÿù»[ÿù»\ÿù¹]ÿù¸^ÿù¸_ÿùµ`ÿø³`ÿ÷²`ÿô²`ÿò¯_ÿð­^ÿï¬^ÿí«]ÿë©\ÿé¨[ÿç¥Zÿä£Wÿá¢Vÿã£Xÿê©Zÿå§VÿãHÿóÀlÿÿúÑÿþï¿ÿó¶\ÿÛšEÿË’IÿË”IÿÑ—IÿÇDÿ¼ˆ@ÿº†>ÿ¹†>ÿ¸…<ÿ±€9ÿ¯~7ÿ±7ÿ«z4ÿ¥u0ÿ¢r.ÿŸo+ÿœm)ÿ˜h&ÿ£s+ÿ¥t(ÿ®nÿ‹^ÿN–»ÿ(çÿ}ìÿŽùÿ©ÿÿ$¾ÿÿ&¿ÿÿ&¹ÿÿ"²þÿ!²ÿÿ$®ùÿ*h°ÿ.7qÿ,D€ÿ+C~ÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿI#ÿ•Tÿ·xÿ±„2ÿ­~.ÿ©t%ÿ«u'ÿ²~*ÿ»‡-ÿ¼ˆ-ÿÀ.ÿÆ“/ÿÈ•/ÿÌ›1ÿÒ 4ÿÖ¤6ÿب7ÿÚª6ÿ߯8ÿè¼?ÿëÀAÿè»=ÿçº=ÿê»?ÿë¾@ÿëÀ@ÿíÁCÿîÃDÿïÃEÿòÄHÿñÃHÿòÄIÿóÃJÿóÄMÿôÃMÿõÂMÿøÅPÿøÃLÿýÞsÿÿýóÿÿøµÿýÆTÿø»Wÿ÷»Zÿø»[ÿø¹[ÿø¸\ÿø¸]ÿøµ^ÿ÷´^ÿô²^ÿó±^ÿó¯^ÿð­^ÿî¬]ÿì«\ÿé©\ÿæ§Yÿä¤Xÿâ¢Xÿà Vÿã£Wÿí«Zÿò«Uÿõ¾mÿýò¿ÿýòºÿî¶]ÿÚ–CÿÌ”JÿÇGÿÊ‘GÿÉ‘HÿÂŒDÿ½‰@ÿ»†?ÿ¸„=ÿ¶ƒ<ÿ°9ÿ®}7ÿ´‚7ÿ±€5ÿ¥v0ÿ¡r.ÿn+ÿœm)ÿ£t+ÿ£s*ÿi ÿªmÿƒ}kÿK™Ãÿ+¦òÿ•ûÿšüÿ!¯þÿ#´þÿ!¯þÿ ¨þÿ¥þÿ ®ÿÿ#®ùÿ)i°ÿ.7qÿ+Eÿ*D}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿ>ÿˆIÿ­jÿ£o$ÿ¤q#ÿªt&ÿ®y(ÿ³~)ÿ¶‚)ÿ¾Œ,ÿɘ1ÿÉ–0ÿÈ–.ÿΞ1ÿÔ£3ÿا5ÿÚ¬6ÿݰ6ÿá³7ÿç·:ÿë¼=ÿé½=ÿé¿<ÿì¿?ÿíÀ@ÿîÄ@ÿïÆCÿñÆDÿòÆEÿòÇHÿóÈHÿóÇIÿóÆJÿôÆKÿôÅMÿôÄNÿôÃOÿõ¿Kÿü×bÿÿüäÿÿúÉÿýÐ\ÿø»Uÿ÷¼Xÿ÷»Yÿ÷¹Zÿ÷¸[ÿ÷·\ÿö¶\ÿô³]ÿó²]ÿó°]ÿð®]ÿï­]ÿí«\ÿë©\ÿé§[ÿç§Zÿå¦Yÿä¤Wÿâ¡Vÿã¡Tÿó³WÿÿÜÿÿþßÿýï¼ÿï¶YÿܘDÿÑ–MÿÌ“JÿÊ’GÿÊ“GÿÇ‘FÿÁŒCÿ¼ˆ@ÿ¹…?ÿ¸„=ÿ·„<ÿ±9ÿ¬z6ÿ¶‡;ÿµ†9ÿ¥v1ÿ q.ÿ q+ÿ›l(ÿ¡p)ÿœm(ÿ–`ÿ§n'ÿ‹yÿF›Ìÿ&öÿŸÿÿ£þÿ §þÿ!«þÿþÿ™þÿ!¦þÿ#µÿÿ%²ùÿ(z°ÿ+Cqÿ.?ÿ.:}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿ ÿ4ÿ|Aÿ­fÿ§q$ÿ¤q&ÿ©t$ÿ±|&ÿ¸‚)ÿ¹‚)ÿ¾‰+ÿÇ–.ÿÊ—/ÿ˘.ÿР0ÿÖ§2ÿÛ«4ÿÞ®4ÿà³6ÿã·8ÿæ¹9ÿé»;ÿë¾<ÿíÂ<ÿïÄ?ÿðÄ@ÿñÇAÿòÉBÿòÉBÿóÊEÿôËHÿöËIÿõÊJÿôÉJÿôÉKÿôÇMÿõÇNÿõÆNÿõÄNÿ÷ÅMÿþêÿÿüÎÿþßkÿ÷¾Rÿö¼Vÿö»XÿöºXÿõ¸[ÿõ·[ÿõ´Zÿô³[ÿñ²\ÿð¯\ÿð­\ÿí¬[ÿìª[ÿê¨Zÿê©[ÿëª[ÿè¦Yÿç¥Wÿë¥VÿòªRÿúÔ‡ÿÿÿçÿÿðÂÿôµVÿã™EÿÜœOÿךLÿÑ•IÿË’EÿÊEÿÅCÿ¾ŠAÿ¼‰@ÿº‡>ÿ¸„<ÿµ‚;ÿ¯~8ÿ«z5ÿ±‚7ÿ³„7ÿ¦u0ÿ£s.ÿ§v.ÿ o*ÿ™i&ÿ”f&ÿžbÿ§r/ÿt‰Šÿ>“Óÿ$™ùÿ!¡ÿÿ!¤þÿ ¢þÿ ¤þÿ!¤þÿœþÿ ¢þÿ!ªÿÿ!¨ùÿ%x°ÿ*Lqÿ,Lÿ-F}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ'ÿo:ÿ«b ÿ±x#ÿ¯~*ÿ­v%ÿ®w%ÿ´~'ÿ¸„(ÿÃ*ÿË—-ÿ˘-ÿΛ-ÿÓ£/ÿÙª2ÿÝ®2ÿà²4ÿä¶6ÿæº8ÿé½9ÿìÀ;ÿîÂ;ÿðÅ=ÿñÇ@ÿòÈAÿôËBÿôÍDÿõÌFÿõÌGÿöÍHÿ÷ÍIÿöÌJÿöËKÿöËKÿöËLÿ÷ÌNÿöÊOÿõÇOÿõÄMÿýÔWÿÿåqÿþ×cÿ÷ÀTÿõ½Uÿõ¼Vÿõ¹Wÿô¸XÿôµYÿó´Zÿò³[ÿñ°Zÿï¯[ÿì¬Zÿì©Yÿé¨Xÿé¦Wÿè§Xÿé¨Yÿê¨Wÿï¯YÿûÀ_ÿÿ݈ÿÿûÞÿÿøÏÿþÒjÿû¹XÿúÃjÿô¾cÿíµ^ÿê¹eÿß®\ÿÕžOÿЖFÿÆAÿ¿‰@ÿº‡?ÿ·„<ÿ´‚:ÿ¯9ÿªz5ÿªy3ÿ­{2ÿ¦v.ÿ¡q,ÿ p,ÿœl)ÿœk&ÿm'ÿªiÿ¢w>ÿj‹™ÿ9“Ûÿ#™øÿ ›þÿ!Ÿþÿ›þÿ"ªþÿ$¬þÿ"§þÿ!¦ÿÿ—ÿÿ›øÿ(u°ÿ*Orÿ+Vÿ-M}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ\/ÿ¡Wÿµv ÿ¯~)ÿ°z%ÿ²{$ÿ·%ÿ½„'ÿÆ“+ÿÏœ.ÿΙ-ÿÑ,ÿÖ¥.ÿÚ¬0ÿß²2ÿâ¶3ÿæº5ÿé½8ÿëÁ:ÿîÄ:ÿðÇ<ÿòÉ>ÿóË?ÿõÌBÿöÎEÿöÎEÿ÷ÎEÿ÷ÎGÿ÷ÎIÿ÷ÏJÿ÷ÎJÿ÷ÎKÿ÷ÍLÿ÷ÍLÿøÐQÿ÷ÎPÿõÊOÿõÆOÿöÅQÿüÊPÿÿÔ_ÿøÁUÿô¼Sÿô¼Tÿó¹Vÿó¸Vÿó¶WÿòµXÿñ²Xÿï°Yÿî®Zÿí­Wÿë«Wÿë«Zÿé«Zÿç¦Wÿë¥SÿùÂfÿÿãŒÿÿô±ÿÿÿîÿÿÿçÿÿï“ÿÿá‡ÿÿì¥ÿÿú³ÿÿú°ÿÿø¶ÿÿÿËÿÿü¹ÿýä£ÿöÕÿìÀeÿÖ›Cÿ½†=ÿ¶„<ÿµ‚:ÿ¯8ÿ¨x4ÿ©y3ÿ°~3ÿ«y1ÿ¡p,ÿm*ÿ›l(ÿ m'ÿ£p'ÿµqÿ™~Qÿ]¬ÿ3 èÿ$§ÿÿ! ÿÿ#§þÿ#¨þÿ#ªþÿ"ªþÿ$­þÿ!¦þÿ§ÿÿ"¬ùÿ'q¯ÿ,Jrÿ-W€ÿ,P}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ ÿK&ÿ—Qÿ³nÿ§q#ÿ­w$ÿ¶%ÿ»ƒ&ÿ¿‡(ÿÅ‘*ÿÍš,ÿÑ+ÿÒ -ÿÙ¦.ÿ߯0ÿã¶1ÿåº3ÿé½6ÿìÀ8ÿîÅ:ÿñÈ<ÿóÊ=ÿõË?ÿöÍBÿõÑCÿ÷ÑFÿøÑIÿøÑJÿøÑKÿøÐKÿøÐKÿøÑLÿøÑLÿ÷ÑMÿ÷ÏLÿ÷ÏNÿøÎOÿõËNÿõÈOÿõÆOÿøÇSÿþÛcÿøÆUÿó¼Pÿô»Qÿò¹Qÿñ·TÿñµUÿð³Vÿï²Wÿë­Vÿî°Zÿ÷ÈxÿùÔŠÿùÓŠÿöÖŠÿóÆrÿùÁdÿÿê”ÿÿÿñÿÿÿÿÿÿÿÿÿÿþðÿÿþÜÿÿúËÿÿò¹ÿÿð®ÿþô¾ÿüñËÿøá°ÿöÜ”ÿýò¹ÿÿÿøÿÿûÆÿî¹TÿÃ…3ÿµƒ:ÿ´‚:ÿ­}7ÿªy4ÿªy2ÿ«y1ÿ¥s.ÿ¤r,ÿ¤r+ÿ n(ÿ›j(ÿ•bÿ­jÿŒ…gÿOš¾ÿ/ªîÿ(´þÿ$«ÿÿ#¨þÿ#¤þÿ#¨þÿ$­þÿ%´þÿ#³þÿ¬ÿÿ›øÿ)Rªÿ1+oÿ+Gÿ*E}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿ ÿ9ÿ…Fÿ¹qÿ±w"ÿ«t#ÿº$ÿÀ‡&ÿ¿‡&ÿÇ)ÿÐ,ÿÔ ,ÿÕ¡+ÿÛ©.ÿá²0ÿæº3ÿè¼5ÿê¿7ÿîÄ8ÿñÈ:ÿôË;ÿõÍ>ÿöÎAÿøÏEÿùÑGÿúÕLÿûÓMÿùÓMÿúÓNÿúÓOÿúÓNÿùÒOÿùÒMÿùÓNÿøÓNÿ÷ÏMÿ÷ÍMÿöËNÿõÉMÿõÇNÿùËQÿÿèmÿùÔ`ÿõ¿MÿúÉYÿõÀRÿð´MÿðµUÿï´Uÿì°Tÿé©Mÿò·^ÿÿòÂÿÿÿíÿÿø½ÿÿñ¢ÿÿõ—ÿÿ÷¬ÿÿü×ÿÿÿÿÿþþþÿþþ÷ÿÿÿÑÿÿ÷›ÿÿÔiÿü¼Nÿö»Lÿí¶KÿäªFÿÛ—7ÿÙŽ-ÿê­>ÿûç¤ÿÿÿàÿôÍÿÒ’6ÿº„9ÿ²:ÿªz5ÿ¨w3ÿ°€6ÿ­~4ÿŸo-ÿ¦u.ÿ®}/ÿ¦r)ÿ“g'ÿ˜`ÿ©r*ÿ{Œ€ÿD¢Ïÿ,´õÿ)·ÿÿ)¸þÿ$¬þÿ"¢þÿ#£þÿ" ûÿ žûÿ"¥ýÿ¨ÿÿ”÷ÿ)L¨ÿ4lÿ1)yÿ1'uÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ&ÿn9ÿ®d ÿµw!ÿ¯v#ÿ·|"ÿ¿„$ÿ†%ÿÊ‘(ÿÓ¢-ÿÕ¡,ÿ× *ÿݪ-ÿâ³/ÿç»3ÿêÀ4ÿìÂ5ÿðÇ8ÿóË;ÿôÎ?ÿöÐAÿùÒDÿûÒHÿûÔNÿüÕRÿüÔTÿüÔUÿûÔUÿûÕUÿûÔTÿûÓSÿúÓQÿúÒPÿùÒNÿøÐMÿ÷ÎMÿ÷ÍMÿöËMÿôÉNÿöÈNÿþånÿýì‚ÿüÚqÿÿð›ÿýà‘ÿ÷Écÿô¾Vÿì®Pÿê­PÿìªKÿö¾cÿÿóÃÿÿúÒÿÿÎhÿþ¼MÿþÕmÿÿê¡ÿÿüëÿÿþÿÿþüúÿþÿëÿÿÿ¤ÿÿñjÿÿÉ\ÿø¶\ÿã¥TÿÎŒEÿLjAÿÊ‘HÿÌ“IÿÏŠ:ÿá¦Mÿûì³ÿÿ÷¿ÿá±Wÿ¸/ÿ®|6ÿªy5ÿ¨v2ÿ±ƒ6ÿ¯‚5ÿžm+ÿ¥u-ÿ®~0ÿŸn)ÿc$ÿ¥dÿ¤|?ÿk’›ÿ:¥Þÿ+µûÿ&²ÿÿ)´ÿÿ%­þÿ# þÿ"¤þÿôÿ‚èÿ‰ïÿ šüÿ Ÿùÿ'_°ÿ3%kÿ2)uÿ0*sÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿT)ÿœSÿ¹vÿµ~%ÿµ{"ÿ¼#ÿÇ$ÿÊ‘&ÿÒœ)ÿÖ *ÿÙ¤+ÿÞ«-ÿá³/ÿç»2ÿìÁ4ÿðÆ6ÿòÊ:ÿôÍ=ÿ÷ÐAÿùÒEÿüÓGÿüÔLÿûÕTÿüÖXÿýÖ[ÿýÖ^ÿü×_ÿü×^ÿüÖ]ÿüÖZÿûÔWÿúÔTÿúÓQÿùÓNÿøÑNÿ÷ÐMÿ÷ÎNÿôËMÿõÉNÿýÕZÿÿî‚ÿÿû£ÿÿÿçÿÿÿ÷ÿÿñ¢ÿúÅOÿï¯Nÿï»^ÿ÷Ælÿþáÿþó°ÿûÜ›ÿö¾bÿï¬Rÿð«Qÿû¼Pÿÿì¥ÿþÿûÿýýüÿÿþûÿÿÿÙÿÿú›ÿþÒfÿò«UÿÚOÿÍ–KÿÊ“HÿÈ’FÿÊ’HÿÀ‹@ÿÁ€-ÿæ´hÿÿûÄÿëÍ‚ÿ»‚.ÿªx2ÿ¨y4ÿ¦w1ÿ­~3ÿ¬}2ÿn*ÿŸn*ÿ¢r*ÿ›l'ÿ™f ÿ­jÿ‘€YÿY—´ÿ1œêÿ)°ýÿ(¸ÿÿ#­þÿ&¥ýÿ"šýÿ$¨ÿÿ •òÿ}Õÿ}Öÿˆêÿ ™õÿ*g±ÿ/,pÿ,8~ÿ+:}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ<ÿˆGÿ½tÿ½ƒ#ÿ·}#ÿ¼#ÿÈ$ÿÉ%ÿÒ›'ÿØ¢(ÿÜ¥*ÿ߬-ÿä´/ÿé¼1ÿíÂ3ÿñÇ6ÿôË:ÿöÎ>ÿøÑDÿûÓHÿüÓMÿüÕSÿüÖZÿýØ`ÿýÙeÿþÙhÿýÚlÿþÚmÿýÙhÿüØcÿü×]ÿûÕYÿúÔUÿúÔQÿùÒOÿ÷ÒNÿøÑOÿõÌMÿôÉMÿöÇJÿ÷ÈIÿûØlÿþé ÿÿúÅÿýäÿù¿JÿúÔiÿþí”ÿÿî£ÿýéŸÿôÇsÿê¦Aÿâ MÿÜŸTÿÝšNÿð«PÿÿÙ{ÿþþ×ÿýÿúÿþÿüÿÿÿÿÿÿýÚÿûÛ{ÿäžFÿÏ‘HÿÈ“GÿÅDÿÂŒCÿÃDÿ¿ŠBÿ½4ÿÞ¦Vÿÿð¨ÿíÔƒÿ»„1ÿ¨t/ÿ§v3ÿ§u1ÿ®z2ÿ¨w0ÿŸp+ÿ q)ÿœk'ÿ—g'ÿ eÿ®t&ÿŠzÿGœËÿ*žóÿ&¯þÿ(¹þÿ%¯þÿ$©þÿ%©ýÿ#¨ÿÿ!ùÿ†ßÿvÏÿ}Ûÿ‡êÿ)_°ÿ/.pÿ/2zÿ0-yÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ'ÿl6ÿ°f ÿ¿~ÿ¸|!ÿ¾ ÿň"ÿË%ÿÕŸ)ÿÝ©+ÿÞ©*ÿá¬,ÿæ´.ÿê¼0ÿïÃ4ÿòÉ8ÿõÍ:ÿ÷Ð?ÿùÑFÿûÓLÿüÕSÿý×[ÿýÙdÿýÙlÿýÛqÿþÜtÿþÜyÿÿÞzÿýÝuÿþÚmÿüØfÿüÖ^ÿûÖYÿúÓUÿùÒQÿøÒNÿ÷ÏNÿöÍLÿôÌLÿñÆKÿð¾Fÿñ¹;ÿöÁ>ÿûßbÿþåqÿûÙjÿÿòyÿüæˆÿõÌwÿì¯Mÿã?ÿÜžKÿÚžPÿÛ PÿÚžPÿâŸMÿö¹Wÿÿèˆÿÿû´ÿÿÿÍÿÿÿùÿÿþøÿúà™ÿÜŸ?ÿÆŠBÿÃŽFÿÂŒCÿÁŒCÿ¾ŠBÿ¼„<ÿÎ’<ÿóÐ|ÿþö«ÿá½dÿ¸.ÿ¨u2ÿ¥t2ÿ«y2ÿµ€4ÿ§u.ÿm)ÿ©}0ÿ¥y.ÿ”f&ÿ¦eÿ¢}?ÿi˜›ÿ7 ßÿ&§ûÿ&¶ÿÿ'¹ÿÿ$±þÿ&²þÿ%°þÿ £þÿ £ÿÿ!¡ýÿˆêÿ‚æÿ‰ïÿ)X¬ÿ2-pÿ/:~ÿ/7|ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿL%ÿ˜Sÿ¿vÿ»~"ÿ¾€ ÿƇ!ÿË"ÿÒ–%ÿܧ)ÿà­+ÿâ¬+ÿç´-ÿì½0ÿðÅ4ÿóË8ÿöÏ<ÿøÑAÿúÓHÿüÕOÿýÖXÿþÙaÿýÚlÿþÛvÿþÝ}ÿþÞ‚ÿþÞ„ÿÿß…ÿþÞ€ÿþÝvÿýÚnÿü×eÿû×]ÿúÕWÿùÓSÿøÑNÿ÷ÐMÿ÷ÎMÿõÌLÿòÈJÿñÃKÿî¾Lÿî¸EÿóÄRÿüê‹ÿûðƒÿøÒYÿì§?ÿâž:ÿÝŸEÿÝ¢OÿߤQÿÝ¡OÿÚŸNÿÙžNÿÚ›Oÿå£Qÿõ·PÿüÒSÿÿìyÿÿþÕÿÿþøÿúÛ”ÿÝž@ÿÄŠBÿÃDÿÂŒDÿ¾ŠBÿº†Aÿ¾‚8ÿߦEÿÿôžÿ÷ì£ÿÌ—Bÿ¯v,ÿ©w3ÿ¤s1ÿ«{5ÿ³‚5ÿ¥u-ÿ›j'ÿ§y.ÿ¢x0ÿ˜dÿ¯kÿ…aÿTžºÿ1¦íÿ&®ýÿ&µÿÿ'¸ÿÿ#³þÿ'³þÿ"ªþÿ¡þÿ£ÿÿ ¤ÿÿœýÿ”ýÿ’úÿ)X®ÿ1.pÿ-G€ÿ+G~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ0ÿx>ÿ·kÿÁ€ ÿÁ…"ÿÊŽ"ÿÍ‘"ÿÒ•#ÿÜ¢'ÿà¨)ÿã«+ÿè³-ÿí¾1ÿñÈ6ÿôÌ8ÿ÷Ï=ÿùÒCÿûÕJÿüÖRÿýÖ]ÿýØhÿþÛsÿþÝ~ÿþà‰ÿþáÿþáÿþáÿþ߈ÿýÞ€ÿýÝuÿýÚkÿü×aÿûÕZÿúÔTÿøÒOÿ÷ÐMÿõÎLÿôËKÿòÈJÿñÃKÿï¿Iÿë»Jÿë·Kÿí¼Sÿë¿Vÿç­Hÿá¥GÿÞ©Mÿß§NÿÞ¤LÿÜ¢MÿÚ¡NÿØžKÿÕœMÿÖ›OÿÛOÿâšMÿêžHÿöºLÿþî¤ÿÿþïÿùÖŒÿÙ™<ÿ‰BÿÅEÿÄŽDÿ¼‰Aÿ¸„>ÿÉ8ÿé¾]ÿÿú«ÿïÕŒÿÇ9ÿ¬{1ÿ¦w1ÿ£t/ÿ¦x3ÿ©x1ÿ¢p,ÿ¢o)ÿ¡n'ÿ“f'ÿžaÿ¥m.ÿs…ˆÿ?—Òÿ)¡õÿ&­þÿ#­þÿ$¯ÿÿ"«þÿ$ªþÿ"¤þÿ£ÿÿ¤þÿžþÿÿÿÿÿŽøÿ%b°ÿ-NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿU*ÿ¡WÿÃ{ÿÆŒ%ÿÏ—%ÿÑ•#ÿÓ–#ÿܤ(ÿâ«*ÿä¬*ÿè³,ÿî¿2ÿòÉ7ÿôÌ9ÿøÎ=ÿúÓDÿü×Mÿü×VÿýØaÿýÚnÿþÜzÿþ߇ÿþá‘ÿþä—ÿþäšÿþâ—ÿþàÿþÞ†ÿýÝ|ÿýÝpÿüÙdÿû×\ÿúÕUÿøÓPÿ÷ÐMÿõÎKÿóËKÿóÉKÿðÄJÿì¿Iÿë»Hÿé¶Fÿå¬<ÿã§=ÿáªHÿ߬Kÿà©JÿÝ¥IÿÜ¢JÿÙ LÿØžLÿÖKÿÔšLÿÔšLÿØMÿÙNÿ×–Mÿä™BÿúÐ{ÿÿÿãÿùà¤ÿÙ@ÿĉ?ÿÆ‘GÿÃŽDÿ¿‹Bÿ¿„:ÿÑ™=ÿöâ‘ÿÿþÅÿëÀjÿÈ.ÿ©z2ÿ¢t1ÿ¡q.ÿ£s-ÿ§s-ÿ¡n+ÿ¢q(ÿn)ÿ”bÿ¨fÿ‘sRÿTƒ®ÿ.çÿ#›ûÿ"þÿ!¡þÿ"¦þÿ"¥þÿ$¥þÿ#¢üÿ šøÿŸþÿ›þÿ—ÿÿ™þÿóÿ&b«ÿ/2qÿ-9€ÿ,9~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ4ÿ~@ÿºnÿɈ!ÿÍ#ÿÐ"ÿÓ“#ÿÞ§*ÿæ·-ÿæ°*ÿè°+ÿî¼/ÿóÅ4ÿõÊ8ÿøÏ=ÿúÓDÿüÕMÿý×WÿýÙcÿþÛpÿþÞ~ÿþá‹ÿÿâ•ÿÿäœÿþäŸÿþã›ÿþã”ÿþàŠÿþÞ€ÿþÝsÿüÛgÿûØ]ÿúÖWÿøÓPÿ÷ÐLÿõÎJÿóËIÿóÈIÿïÄGÿì¾Gÿë½Gÿë¹Jÿè¶Jÿå²Iÿã­HÿߨGÿܧIÿÛ¤IÿÙ¡Hÿ×JÿÕ›IÿÓ™KÿјJÿÒ™IÿÓšKÿÓ˜KÿÓ–Iÿã¡GÿúÒxÿÿÿåÿüî¶ÿâ§EÿÆŠ>ÿ¿ŒCÿ¼‰@ÿ¿Š?ÿÇŠ;ÿߢ@ÿýå›ÿÿÿÜÿóØŒÿÇ‘9ÿ¤m%ÿ o+ÿ¥t/ÿ«z1ÿ¨x.ÿŸn)ÿ›j'ÿ‘f&ÿ aÿ©p(ÿu€ÿ<‡Îÿ&˜ôÿ" þÿ “þÿ# þÿ#©þÿ#¢þÿ$¢þÿ$Ÿýÿôÿ™úÿ šüÿ’÷ÿõÿîÿ*N¡ÿ3jÿ.0~ÿ-1|ÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿV+ÿ¡XÿÈ}ÿʇ!ÿÎŽ!ÿÕ“"ÿÛ%ÿä±*ÿè´+ÿê°+ÿí¸/ÿòÃ3ÿõÉ7ÿ÷Î>ÿúÔFÿü×NÿýØWÿþÙcÿþÛpÿþÞÿþá‹ÿÿã•ÿÿåœÿÿäžÿþäœÿþã–ÿþáŠÿþÞ~ÿþÝsÿüÚhÿûØ]ÿúÕVÿøÔPÿ÷ÑLÿôÎJÿòÊGÿñÆGÿîÂGÿì¿Fÿì¾Gÿê»IÿåµGÿã°Eÿá«EÿÞ¨FÿܦHÿÚ£HÿÖ HÿÖIÿÔ›IÿЖHÿΕIÿЗIÿЗJÿΖIÿÔ•Eÿí´Rÿÿî©ÿÿÿåÿûáŽÿã¥BÿÈŒAÿ¼ˆ@ÿ¶„=ÿ¹†=ÿÀŠ=ÿÕ–>ÿï¼^ÿüç¦ÿÿþÅÿîØ†ÿÆ“=ÿ¯u)ÿ­t,ÿ¯z/ÿ¢s-ÿœj'ÿ˜f&ÿ™cÿ®gÿ•{RÿX‹¬ÿ/”äÿ#¡ûÿ!¤þÿ# þÿ%¯ÿÿ$­ÿÿ#¥ÿÿ#¤ÿÿ# ÿÿ ˜ýÿ “õÿŒðÿ‡åÿïÿ—öÿ(R¦ÿ1"iÿ-1}ÿ,1}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ3ÿz>ÿ¼m ÿχÿÏŽ"ÿÕ’"ÿÚ—"ÿá©&ÿè¶*ÿê±,ÿî·.ÿòÃ2ÿõÇ7ÿøÐ?ÿúÖFÿü×MÿýØVÿýÚaÿþÛmÿþÞzÿþáˆÿþã’ÿþä˜ÿþã™ÿþã˜ÿþã’ÿþá‡ÿýß{ÿýÜpÿüÙeÿû×[ÿúÖSÿøÓPÿöÐKÿôÍIÿòÊGÿîÆEÿíÀEÿë½EÿéºDÿå¶Eÿã²Dÿá®EÿÞªEÿܧDÿÛ¤FÿÙ¡GÿÔGÿÔHÿÔ›HÿЗHÿÍ•HÿÍ”HÿΗJÿÓžLÿÕšDÿë¾^ÿÿüÇÿýí´ÿíµNÿÖ•AÿÅŽDÿº‡>ÿµ„<ÿµ„;ÿµƒ;ÿ¸„;ÿÇ‹4ÿ×™;ÿìÅlÿÿ÷¡ÿüî”ÿàµUÿÀ„,ÿ¬q$ÿ¢j#ÿ¡i$ÿ­s(ÿÁvÿ±y/ÿt‡…ÿ>”Ïÿ(¤ôÿ"©þÿ¤þÿ#­þÿ%®þÿ#¦ýÿ ¡÷ÿ"¤úÿ!Ÿüÿ"Ÿÿÿ"“õÿƒåÿ|ÖÿŒêÿ•õÿ'Zªÿ0%dÿ,4yÿ*8}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿM&ÿ›RÿÌ~ÿÒ‹"ÿÓ!ÿÛš#ÿá¦%ÿä«(ÿè­)ÿí´,ÿò¿0ÿöÅ5ÿøÏ<ÿúÔCÿüÔIÿû×SÿýÙ]ÿþÚiÿþÝtÿþà€ÿþáŠÿþáÿþâ‘ÿþáÿþáŠÿþà€ÿýÞwÿýÛkÿüÙbÿûØXÿùÖQÿøÓNÿöÐIÿóÍHÿñÉFÿîÅEÿìÀDÿé»Dÿç·Cÿâ³Bÿá¯BÿÞ­DÿÛ¨DÿÚ¤DÿØ¡CÿÕŸDÿÒ›EÿÑšFÿÑ™EÿЙGÿΖGÿË“GÿË“HÿΘHÿÑ—@ÿíÇtÿÿÿÃÿöÐ{ÿÚ“5ÿÉDÿÁŒBÿ¸†<ÿµƒ<ÿ³:ÿ°9ÿ¬}8ÿ¨w2ÿ©o$ÿ»{!ÿÛ¬SÿóÞˆÿýäwÿíË[ÿÓ¦HÿÇŠ3ÿÍ›?ÿè²>ÿÞ—(ÿ–‡[ÿQ•²ÿ/¢çÿ#¬üÿ¦þÿ£þÿ#©ÿÿ ’ðÿ‹æÿâÿ“ìÿ šùÿ#£þÿ$Ÿýÿˆêÿ~Øÿ‰ãÿ‰èÿ(V¦ÿ/%`ÿ-2pÿ*5sÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ)ÿl5ÿµf ÿÔˆÿÔ"ÿÙ–!ÿßž#ÿâ£&ÿç©'ÿì°*ÿñ¹.ÿôÃ4ÿöÉ9ÿøÌ=ÿúÒEÿû×NÿýÙXÿþÛbÿþÛmÿþÞwÿþà€ÿþà„ÿþà…ÿÿß„ÿþÞÿþÝxÿþÜoÿüÛgÿü×^ÿú×UÿùÔOÿöÓKÿôÐHÿðËEÿïÇBÿíÃDÿé¾BÿçºBÿå¶Aÿá±Bÿß­BÿÞ«AÿÛ¨BÿؤCÿÕŸCÿÑCÿÑ›CÿΗDÿÍ–CÿϘFÿјFÿË“EÿÅŽCÿ¿†<ÿÎ<ÿôÕ˜ÿÿÿÒÿôÅkÿØ“:ÿÈ•Hÿ½Œ@ÿ³‚:ÿ³:ÿ°8ÿ¬|7ÿ©y5ÿ¥v3ÿ¢t3ÿ¦r.ÿ°r'ÿ½|-ÿ×¢?ÿúætÿÿúœÿúã„ÿÿælÿüÌHÿ¼—Fÿi‘ÿ8¤Õÿ(±õÿ#¯þÿ–üÿšýÿ#¥ÿÿˆåÿ|Óÿ…ãÿŽîÿ ûÿ#¦ÿÿ!ŸÿÿôÿŠêÿ‘ïÿŠèÿ'V£ÿ.%^ÿ-.dÿ,-dÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ?ÿ‡FÿÉzÿÙ’!ÿØ‘ ÿݘ!ÿå«'ÿê´)ÿë¯)ÿî³+ÿóÀ3ÿöÌ:ÿøÍ=ÿúÎAÿüÓIÿý×SÿþÙ[ÿþÛdÿþÝnÿþÞtÿÿÞwÿþÞxÿýÞyÿþÝtÿþÜmÿýÛgÿüÚ`ÿûÖXÿúÖRÿøÔMÿöÒJÿóÎFÿòÎHÿñÊGÿìÂBÿè¼Aÿã¸Aÿâ´Aÿà°Aÿß­AÿݪAÿÙ¦BÿÕ¢AÿÕžBÿÓžDÿÑœCÿË—CÿÊ”CÿÌ”EÿÍ•DÿÈ’EÿÀ‹Bÿ¼0ÿØ FÿüðÄÿÿùÊÿò·SÿÕ“>ÿÅ—Gÿº‹?ÿ²8ÿ®~8ÿ¬}6ÿ«z6ÿ§w3ÿ¦u1ÿ¬z3ÿ«z2ÿ¨w.ÿªs&ÿ°pÿÒCÿíØƒÿïá†ÿëºHÿÅŠ/ÿ€ˆpÿJ¤Âÿ-¶íÿ"¶üÿ"§ÿÿ‹ùÿ…õÿ" üÿ#²õÿšìÿ“úÿ ™ùÿûÿšûÿ! þÿ!œüÿ •úÿ!žþÿ"•ôÿ)P™ÿ1Jÿ-&Vÿ,%VÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿS(ÿ¡XÿÓ…ÿÙ‘"ÿÙ”!ÿä­(ÿëÀ.ÿë¶+ÿï·+ÿóÄ2ÿöÏ@ÿøÕGÿùÎ@ÿûÎBÿüÓLÿüØSÿýÛZÿýÛaÿþÝfÿþÜjÿýÛkÿýÜjÿýÛiÿýÚcÿüÙ]ÿûØXÿú×SÿøÕOÿ÷ÓJÿõÐIÿóÌCÿõÒOÿòÐQÿêÀ?ÿçº?ÿâ¶?ÿß²?ÿß®?ÿܬ?ÿÙ¨?ÿÖ£@ÿÓ ?ÿÓAÿÓCÿÏ›CÿË–AÿÉ”BÿÇ‘BÿÅBÿÃEÿÆŠ;ÿÔ“2ÿðÏxÿÿÿ×ÿúÜ“ÿÝ›:ÿÁˆ=ÿ·†=ÿ´:ÿ±}8ÿ®}6ÿ¬|5ÿ°€7ÿ®}4ÿ«y2ÿ¯|2ÿªw.ÿ§w/ÿ¯‚2ÿ­y-ÿ¨m%ÿ¬w(ÿ´uÿ¶hÿxOÿY›«ÿ8´äÿ(Ãúÿ#Áÿÿ ¤ÿÿ"“üÿòÿ‘÷ÿ(Áÿÿ"±ÿÿ"£ÿÿ#¥üÿ!žýÿ•úÿ"¨þÿ#§þÿ"šþÿ"œýÿ"’ñÿ)Gÿ0Aÿ+&Uÿ*(WÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ*ÿg3ÿ²cÿÙ‹ÿÜ•!ÿß¡$ÿæ±*ÿê³*ÿï»,ÿòÆ0ÿóÉ<ÿöÔFÿøÓAÿúÍ>ÿúÏEÿûÕLÿýØQÿýÙUÿýÛZÿýÚ^ÿýÚ_ÿýÛ^ÿüÙ\ÿûÙZÿúØUÿùÖPÿøÕMÿöÓIÿõÐFÿóÎDÿñÉBÿòÌGÿîÊIÿè¾=ÿå¹>ÿâµ>ÿÞ°=ÿÛ¬=ÿب=ÿÕ¦=ÿÔ¡=ÿÑž=ÿÏš?ÿ˘?ÿÉ•AÿÈ”?ÿÈ’@ÿÅ‘AÿÂAÿÌŽ:ÿá¢AÿõÓ„ÿÿüÅÿúç›ÿݦKÿ¾†7ÿ²ƒ:ÿ¯~8ÿ¯}7ÿ²€7ÿ³7ÿ­|5ÿ±€6ÿ´5ÿ­|2ÿ§w0ÿ¢q-ÿžn*ÿ¡p*ÿ¤t+ÿ•g(ÿ‘Yÿ¥Xÿœn:ÿj‘–ÿ@®Øÿ-¼öÿ%Ãÿÿ'Ìÿÿ"»þÿ#·ÿÿ!¯ûÿ–ûÿ’üÿ"—ýÿ"Ÿúÿ œøÿ šþÿ!¢þÿ#¦üÿ!œ÷ÿ ïÿŠéÿwÑÿ'?ƒÿ.Eÿ+%Tÿ*'UÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ7ÿz<ÿÂp ÿà’ÿÞ—"ÿßš!ÿå¢%ÿë®(ÿð¿.ÿóÆ2ÿõÉ6ÿ÷Í:ÿ÷Í<ÿúÌ?ÿûÐDÿûÔIÿüÖLÿüÙPÿûØSÿûÙUÿûÙUÿû×Sÿù×QÿøÖNÿ÷ÕKÿõÓHÿôÑDÿóÏDÿñËBÿîÅ@ÿëÃ=ÿéÀ=ÿæ»=ÿã¸<ÿá³<ÿÜ®;ÿØ©;ÿצ<ÿÔ£=ÿÑŸ=ÿÏ›=ÿË—=ÿÇ”=ÿÅ’>ÿÄ‘>ÿÃ@ÿÃŽAÿÉŒ5ÿã¤;ÿûÝ“ÿÿÿíÿùè±ÿÚ£Bÿ¹~/ÿ°:ÿ¯8ÿ¯~7ÿ´†:ÿ»‹<ÿ´8ÿ¬y3ÿªx2ÿªy1ÿ§w/ÿ¡r-ÿœm*ÿ˜h&ÿm(ÿ¤x.ÿžn%ÿ©dÿ©u.ÿz‹ÿE˜Ëÿ-«ïÿ'½ýÿ&Äÿÿ#Äÿÿ"Æþÿ%Òÿÿ&Ôÿÿ ·ÿÿ ’ýÿ!Žûÿ!œõÿ–ôÿ" ýÿ"£ÿÿ•úÿ‹ïÿˆãÿŠâÿyÍÿ'@ƒÿ/Mÿ+!Qÿ* NÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿB!ÿ‰GÿÉyÿâ– ÿàš#ÿâ"ÿæ¢$ÿë±)ÿñÂ/ÿóÃ1ÿóÀ3ÿôÄ7ÿ÷É;ÿùÎ=ÿøÐBÿúÒDÿúÖGÿúÖJÿù×Kÿù×Kÿù×KÿøÖJÿ÷ÔGÿõÓEÿóÏDÿòÎBÿðÌAÿîÈ>ÿêÃ<ÿçÀ;ÿå¼;ÿâ·<ÿà´:ÿݯ;ÿÚ«:ÿا:ÿÖ¥<ÿÕ¢<ÿО=ÿÌš=ÿʘ=ÿÉ–>ÿÅ’>ÿÀŒ=ÿ¾†4ÿËŠ-ÿä¦Cÿúß•ÿÿÿîÿÿôÉÿé³Tÿ½~+ÿ¬{7ÿ­}7ÿ¬z6ÿ¬z5ÿ²ƒ8ÿ¹‰:ÿ´‚6ÿ©x1ÿ£s.ÿ q,ÿ§t.ÿ¤s+ÿ™j'ÿši&ÿ r+ÿ¤v*ÿ±pÿ³v'ÿ‡ŽqÿQ£½ÿ0¢éÿ!žùÿ¯ÿÿ%Àÿÿ"»ÿÿ#Àÿÿ'Òÿÿ%Öÿÿ)Õÿÿ(Çÿÿªþÿ!ªüÿ#¬üÿ#«þÿŸýÿ•ûÿœøÿ!Ÿóÿ"¢÷ÿ"–ðÿ)R¡ÿ/!^ÿ,&Zÿ,!SÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ$ÿMÿÏÿæ#ÿãŸ%ÿâœ"ÿæ¡$ÿë²*ÿï¼/ÿð¹/ÿò¹1ÿóÂ6ÿõÆ8ÿ÷É;ÿøÌ=ÿøÑAÿøÓDÿ÷ÓCÿ÷ÓDÿ÷ÔDÿöÔDÿõÒBÿóÐ@ÿòÍ@ÿñÌ>ÿïÉ=ÿìÅ<ÿèÀ;ÿå¼:ÿã¸9ÿàµ;ÿܯ9ÿت9ÿÖ§9ÿÕ¤:ÿÒ¡:ÿÑž:ÿΛ;ÿÉ—;ÿÈ—;ÿÇ“>ÿÃŒ9ÿÅŠ2ÿÑ—7ÿç±Tÿüá¦ÿÿÿçÿþó¸ÿôÉ]ÿÖ•6ÿ¶9ÿ¬|7ÿ«{5ÿªy4ÿ¨x3ÿ§v1ÿ«z2ÿ¯}3ÿ¤t.ÿ›l*ÿ¡r,ÿ®2ÿªw,ÿj(ÿm*ÿ›j%ÿ¤eÿ³r!ÿ‘‹fÿVŸµÿ6¯ãÿ)°øÿ£þÿ¤ÿÿ¯þÿ"³þÿ"´ÿÿ$»ÿÿ"Äÿÿ(Õÿÿ)àÿÿÃÿÿ¢ÿÿ¢ÿÿ¤þÿ#°þÿ(·ÿÿ%¸ÿÿ#´ÿÿ¬ÿÿ˜ûÿ)R¨ÿ2^ÿ.%]ÿ-#VÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ"ÿR(ÿ—RÿÒÿæ™#ÿãœ#ÿâœ"ÿèª'ÿìµ+ÿí²+ÿð²-ÿñ¹0ÿò¼2ÿô¿4ÿõÃ6ÿõÇ:ÿöÊ=ÿõÊ=ÿõË=ÿôÍ=ÿóÎ>ÿòÎ=ÿðÍ<ÿïÊ;ÿîÉ<ÿìÅ;ÿèÁ:ÿç¾:ÿä¹9ÿá¶8ÿß³9ÿÚ­9ÿÖ¦7ÿÒ£7ÿР8ÿÏž8ÿÌ›9ÿɘ9ÿÆ”9ÿÑ:ÿÀŒ8ÿË‘5ÿä¶UÿõâšÿþõÐÿÿÿâÿûçŸÿä±DÿÌ“4ÿ¼†:ÿ°}8ÿ®}6ÿ°6ÿªy3ÿ¤u0ÿ¢s/ÿ¢r/ÿ£s.ÿ q,ÿŸo+ÿ¨z/ÿ±ƒ1ÿ©v,ÿj(ÿ˜g#ÿ£cÿ¯nÿ’‡]ÿ]Ÿ­ÿ5§ßÿ$¥õÿ!ªýÿ ­þÿªþÿ¨þÿ!©þÿ!¬þÿ ¦þÿ­þÿ$Çÿÿ(Úÿÿ(Ôÿÿ ªþÿšþÿ›þÿ"ªþÿ*¹þÿ%·þÿ!µþÿ²ÿÿ!§÷ÿ)^¦ÿ/(aÿ*6nÿ(9mÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ&ÿU'ÿ—NÿÏ~ÿæœ!ÿäŸ$ÿä£%ÿè¬&ÿë±(ÿí°*ÿî°,ÿð·/ÿò»2ÿñ¿3ÿñ¿3ÿò¾5ÿñÀ6ÿñÂ7ÿðÅ8ÿïÅ8ÿîÅ8ÿìÃ6ÿëÁ7ÿéÀ7ÿç¾6ÿä¼8ÿãº7ÿá¶7ÿݱ6ÿܯ6ÿØ©7ÿÔ¥6ÿÒ¢7ÿÑŸ7ÿÍœ8ÿÈ—8ÿÇ–7ÿÆ”9ÿÃ8ÿÉ’5ÿè¼\ÿþó²ÿÿþÇÿÿï¯ÿûÜŠÿä«Cÿ½~*ÿ¬x4ÿ«{6ÿªy4ÿ¯}5ÿ±~4ÿ¦v0ÿ¡s.ÿ£s.ÿ¡q-ÿžm*ÿ¢r,ÿ©z.ÿ«z-ÿ¥s*ÿši'ÿ•b ÿ¤eÿ°o ÿ”…]ÿ_žªÿ9©Üÿ%¦ôÿœýÿ ÿÿ¨þÿ©þÿ!®þÿ ªþÿ ¬þÿ"¯þÿ¯þÿ#Áÿÿ$Îÿÿ-Ùÿÿ0Ëÿÿ#¸ÿÿ¬ÿÿ™ýÿ–ùÿ ¦ýÿ©þÿ¯ÿÿ'¼ùÿ(±ÿ$Bpÿ&I‚ÿ%J€ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ&ÿR'ÿ’LÿÌ|ÿå™ ÿå%ÿä %ÿèª'ÿé¬)ÿê­*ÿí´-ÿïº0ÿðÀ3ÿïÀ2ÿðÁ4ÿðÅ7ÿïÀ5ÿí¼3ÿì»3ÿê»4ÿéº3ÿç¹4ÿä·3ÿâµ2ÿß²3ÿݱ3ÿܯ3ÿÛ®5ÿש4ÿÔ¤5ÿÑ¢5ÿП5ÿÎ5ÿÊ™5ÿÉ—7ÿÈ•8ÿÈ•:ÿÍ•7ÿâ¨?ÿýè›ÿÿÿßÿ÷Ôrÿê¬3ÿá¡=ÿˆ6ÿ«x5ÿ©x3ÿ¦w1ÿ§v2ÿ¦w0ÿ¤u/ÿ£s.ÿ¦w/ÿ©x/ÿ¡p-ÿl*ÿ¢q+ÿ¨x,ÿ¤r)ÿ”f%ÿ_ÿ£bÿ±s&ÿ“„cÿ\“¬ÿ9¦Ýÿ&§óÿ¢ýÿ¨ÿÿ©ÿÿ£þÿ£þÿ ±þÿ ²þÿ °þÿ²þÿ´þÿ#Âÿÿ!Éÿÿ&Ôÿÿ.Ùÿÿ'Ðÿÿ'Èÿÿ#¯ýÿ’úÿ žÿÿœÿÿ¥ÿÿ#°ùÿ&|±ÿ%Esÿ(Fÿ(D~ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ"ÿL$ÿŠFÿÆuÿä–ÿæ%ÿâ%ÿã $ÿç§'ÿè«)ÿè¬)ÿë³-ÿë¹/ÿíÁ4ÿíÈ9ÿì¿3ÿê¸0ÿéº2ÿé¾5ÿèÂ:ÿç¾7ÿã¶2ÿß°2ÿܯ2ÿÛ¯4ÿت2ÿÙ«4ÿÓ£2ÿÏ2ÿÌ›2ÿÉš3ÿɘ4ÿÌ›7ÿÌš8ÿÅ’7ÿÅ‘9ÿÕ™7ÿîºJÿÿö±ÿÿýìÿôÑoÿב#ÿÀƒ3ÿ®~6ÿ§w2ÿ¨w1ÿ§v0ÿ©w1ÿ¨x0ÿ¢t.ÿ¡q-ÿ§v/ÿ¨w.ÿžm*ÿšk(ÿ¡o*ÿ¡p*ÿ˜j&ÿ•aÿ¤cÿ­s+ÿއlÿZ“³ÿ8 áÿ*­õÿ"«üÿ¨þÿ­þÿ ±þÿªþÿªþÿ±þÿ°þÿ±þÿ²ÿÿ!»ÿÿ%Êÿÿ"Éÿÿ"Íÿÿ%Öÿÿ&Öÿÿ)Òÿÿ&Àÿÿ¡þÿ!œýÿ"£üÿ$µÿÿ¤÷ÿ%a«ÿ,9sÿ*Dÿ(D}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿE!ÿ@ÿ»l ÿÞŽÿä™#ÿà™#ÿáœ%ÿãŸ&ÿã¡&ÿä¥(ÿæ©+ÿè®,ÿæ±.ÿæ±-ÿè·1ÿé¼3ÿç½6ÿåÁ;ÿæ¾7ÿä¹3ÿá´3ÿß´5ÿݳ6ÿÔ¥2ÿÒ¡1ÿΛ0ÿÉ—/ÿÈ–0ÿÆ–2ÿÇ–4ÿÌ›9ÿÉ—8ÿÁŽ5ÿÁŒ6ÿÏ“8ÿì¸Fÿÿð‡ÿÿÿãÿùé±ÿÙ :ÿ²y+ÿ§w2ÿ¥t0ÿ¤s/ÿ§u0ÿ«y0ÿ¬{1ÿ¢s.ÿœl*ÿžn*ÿŸn*ÿ›k(ÿ™j&ÿ˜h(ÿ•e$ÿšbÿ¨fÿ§u5ÿ„ŠzÿU›»ÿ6âÿ(žòÿ%­ûÿ$°ÿÿ¦þÿ¡þÿªþÿ ²þÿ®þÿ£þÿ£þÿ°þÿ#»ÿÿ&Äÿÿ'Ìÿÿ'Ïÿÿ&Ïÿÿ#Óÿÿ&Öÿÿ(Óÿÿ#½ÿÿþÿ†ïÿ’ëÿ&½þÿ$¨ùÿ'\¬ÿ*:qÿ'M€ÿ%K}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ;ÿn7ÿ©]ÿÓ…ÿã›!ÿáš%ÿÞ˜$ÿà &ÿá¤'ÿá£(ÿâ¥(ÿà¡'ÿߢ)ÿáª-ÿá¬-ÿݧ,ÿܨ.ÿܪ.ÿ߯0ÿÝ®1ÿÙª1ÿÖ¥0ÿΛ/ÿÌ™.ÿË™/ÿȘ0ÿÅ”0ÿÆ”1ÿÅ”2ÿÇ“5ÿÈ”7ÿÆ‘6ÿÈ7ÿØš=ÿò¹Aÿÿã]ÿÿÿÇÿýóÂÿÜ«@ÿ­u$ÿ£r1ÿ£r.ÿ¡p,ÿ¡p-ÿ¡q-ÿ p+ÿœm*ÿŸo)ÿ¤s*ÿžl(ÿ™j'ÿ—h%ÿ”bÿ¡eÿ­mÿžxGÿuˆŠÿNŸÇÿ5ªêÿ(Ÿôÿ!“õÿ#¢ûÿ$¯ÿÿ ¥þÿ þÿ©þÿ ´þÿ©þÿ’þÿœþÿ!´þÿ"»þÿ"¾ÿÿ$Åÿÿ'Îÿÿ'Ïÿÿ$Ðÿÿ%Òÿÿ%Íÿÿ"½ÿÿŸþÿ†ðÿ€éÿ úÿ"Ÿùÿ)^®ÿ*9pÿ(K€ÿ'G}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ.ÿY+ÿ“PÿÆ}ÿÝÿß•"ÿÞ&ÿÜœ%ÿÛž$ÿݤ'ÿà§)ÿÞ¥)ÿÚ'ÿØœ(ÿÙ¤+ÿÙ¢+ÿÔœ)ÿÓœ*ÿÑœ+ÿϘ*ÿÌ•+ÿÉ“,ÿÊ–.ÿС3ÿП5ÿÓ0ÿÃ’0ÿÑ0ÿÁ1ÿÄ3ÿÌ–7ÿá§>ÿô¹CÿýËKÿÿî•ÿÿÿÞÿûáŒÿÏ•,ÿ¤o(ÿŸp.ÿ o+ÿœl)ÿ›l)ÿ™k)ÿ—i'ÿŸn)ÿ¨t+ÿ¢q)ÿ–g'ÿ•d!ÿcÿ¨eÿªjÿoDÿb}ÿB™Òÿ3°ðÿ+²úÿ#£üÿ!œûÿ%¨þÿ&±ÿÿ"­þÿ"ªþÿ!¯þÿ ²þÿ­þÿžþÿ¨þÿ"¶þÿ!·ÿÿ¸ÿÿ!Áÿÿ$Çÿÿ$Ëÿÿ'Ðÿÿ&Íÿÿ#Æÿÿ#¾ÿÿ °þÿ«ýÿŸúÿ’÷ÿƒçÿ&Q¤ÿ.5sÿ*G€ÿ)C}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"ÿF!ÿw?ÿª_ÿÌ{ÿÛÿÛ”$ÿ×”$ÿÕ˜$ÿÙ &ÿÚ¢(ÿÔ—%ÿÔ—&ÿÚª-ÿØ¥,ÿÏ–'ÿÌ‘&ÿÉ‘(ÿË“*ÿË•+ÿÅ*ÿÄ‘,ÿÑŸ3ÿà¥-ÿÈ‘)ÿ½‹.ÿÑ2ÿ¿2ÿ¼‰2ÿÕš7ÿú¾=ÿÿÐ7ÿÿàjÿÿÿÞÿþí½ÿâ«9ÿ°t!ÿœk+ÿžo+ÿ¢s+ÿ¥w,ÿ q*ÿm'ÿšl'ÿžm)ÿœk'ÿ“c"ÿ–_ÿ£cÿ«p!ÿžt>ÿvhXÿLgƒÿ2…Çÿ,«ôÿ)¶ýÿ&°þÿ%«ÿÿ%ªÿÿ&¬ÿÿ$«þÿ#¬þÿ#±þÿ"³þÿ!³þÿ"¶þÿ ´þÿµþÿ ¶þÿ!·þÿ!½ÿÿ"Áÿÿ#Ãÿÿ&Èÿÿ&Êÿÿ&Èÿÿ&Æÿÿ#¾ÿÿ!¹ÿÿ"»ÿÿ!¹ÿÿ›üÿxâÿ%O ÿ-8uÿ*F€ÿ)F}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ0ÿW*ÿ†Eÿ³e ÿÑ…ÿÛ• ÿו$ÿÒ‘$ÿÎ$ÿÍ#ÿÌŽ#ÿÏ–&ÿÒ›)ÿË‘&ÿÇŒ%ÿÆŒ&ÿÆ(ÿÅ)ÿÂ*ÿ¿‹(ÿס(ÿóÌDÿá§0ÿƈÿÌ–,ÿË–5ÿÒ˜8ÿê´AÿÿÝZÿÿêÿÿú­ÿþó®ÿá¬Oÿ·zÿ§w-ÿ¥v.ÿŸn(ÿ r+ÿ©{-ÿ£s*ÿ›k(ÿ—i'ÿ–d!ÿœeÿ¥gÿ­oÿ¤|7ÿ‰‹iÿbŒšÿ=…·ÿ'‰Õÿ!›óÿ"°þÿ!­ÿÿ!¤þÿ%¬þÿ'²þÿ$©þÿ!¡þÿ#©þÿ$±þÿ!²þÿ!µþÿ!¶þÿ¶þÿ¶þÿ!»ÿÿ!¾ÿÿ"Áÿÿ#Àÿÿ"½ÿÿ$Àÿÿ!¾ÿÿ!½ÿÿ&Ãÿÿ#Àÿÿ"¼ÿÿ!¼ÿÿ ºÿÿ¨ÿÿóÿ%]¬ÿ-5rÿ,;}ÿ+={ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ<ÿd2ÿ‘Pÿºu ÿЈÿÒ‹ÿ· ÿÏ•&ÿË“'ÿÄ…"ÿÇŠ$ÿÅ‹$ÿ‡$ÿ¿†$ÿ¿‡%ÿ¾‡(ÿÁˆ&ÿГÿðÇWÿþøÁÿúÞŽÿë¸Cÿé¸>ÿè©)ÿô¹0ÿüÞUÿÿû¼ÿÿÿíÿÿ÷§ÿíÂNÿÃ…#ÿªu)ÿ­3ÿ©|/ÿ˜i'ÿ”f&ÿ—i'ÿ–g%ÿ”bÿ™`ÿ¦gÿ³vÿ¬~8ÿ’‰_ÿq›‘ÿLžÀÿ3¡ßÿ(¨óÿ ©þÿ¬ÿÿ °ÿÿ¬þÿ¥þÿ"¬ÿÿ'¶ÿÿ&°þÿ$«þÿ%°þÿ$³þÿ!³þÿ"µþÿ!µþÿ´þÿ ·þÿ#Àÿÿ#Äÿÿ"Áÿÿ!¾ÿÿ »ÿÿ »ÿÿ"¿ÿÿ"¾ÿÿ$Âÿÿ#Ãÿÿ"½ÿÿ$¾ÿÿ%¿ÿÿ ¹ÿÿ!¥úÿ&b²ÿ,1pÿ+8}ÿ*8{ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ#ÿ?ÿe6ÿOÿ­c ÿÁrÿÑÿÓ—#ÿÉŒ#ÿÁƒ#ÿÀ‡&ÿÀ‰'ÿ¼„$ÿÀ‡%ÿň&ÿÓ•ÿðÅCÿþò¼ÿÿÿëÿÿýßÿþõÊÿýíªÿýÞ]ÿÿä\ÿÿú ÿÿÿìÿÿèžÿâ®@ÿ†)ÿ´~,ÿ¤t-ÿŸq*ÿ¡p*ÿ•e#ÿ‘_ÿ•^ÿ aÿ§eÿ¨fÿ£p2ÿ‘ƒ_ÿq“ÿOž¹ÿ8¨Ùÿ*¨îÿ$®úÿ#´ÿÿ °ÿÿ ±þÿ²þÿ±þÿ¯þÿ ²þÿ%·ÿÿ(ºÿÿ(¹þÿ&·þÿ$¶ÿÿ"·þÿ"¹þÿ"¹þÿ ¸þÿ ºþÿ"¿ÿÿ$Äÿÿ"Âÿÿ#Áÿÿ$Ãÿÿ%Æÿÿ&Êÿÿ$Èÿÿ'Êÿÿ&Çÿÿ"¾ÿÿ#¼ÿÿ%¿þÿ$Àÿÿ$²ùÿ'd°ÿ+/qÿ*9|ÿ)8zÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ#ÿ=ÿ^.ÿBÿŸVÿ¸p ÿƃÿÅÿȃ ÿÔœ*ÿØ /ÿÜ£3ÿç¯1ÿõÚcÿÿ÷Äÿÿÿ®ÿÿ÷zÿÿÿ•ÿÿÿ²ÿÿÿÊÿÿþÞÿÿþÝÿÿÿÞÿýê•ÿã§*ÿ´pÿ¡l%ÿ£o$ÿšeÿœcÿ§jÿ¤cÿ¤bÿªkÿªr,ÿyFÿ…}fÿi{ŠÿMеÿ8¥Ùÿ*®ìÿ§øÿ¥ýÿ!ºÿÿ%Ãÿÿ µþÿ¬þÿ¬þÿ³þÿ·þÿ!´þÿ#¶ÿÿ&¼ÿÿ'¾þÿ%»ÿÿ$¹ÿÿ$¼ÿÿ#¼þÿ"¼þÿ#¼þÿ"½ÿÿ!¾ÿÿ$Åÿÿ&Éÿÿ&Éÿÿ(Îÿÿ(Ïÿÿ&Ìÿÿ&Æÿÿ%¾ÿÿ#·ÿÿ"¸þÿ%¿ÿÿ"¹þÿ"ºÿÿ%¶ùÿ&n°ÿ*4rÿ)9}ÿ(9{ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ5ÿM%ÿj6ÿ‡Kÿ›Vÿ­b ÿÉ„ÿá$ÿò¹7ÿÿÖ@ÿÿÿ¬ÿÿÿýÿÿÿ–ÿÿýIÿÿÿ_ÿÿé`ÿÿé}ÿÿÿ×ÿÿþØÿÿ߀ÿï©)ÿÂwÿ«iÿ­nÿ«kÿ¥bÿ¬kÿ±u&ÿ£n2ÿ™wFÿhÿx“Šÿ^Œ©ÿHŽÄÿ4Úÿ(ìÿ$²øÿ²ýÿ¨ÿÿ¯ÿÿ#½ÿÿ"¹ÿÿ®þÿ­þÿ­þÿ³þÿ#·þÿ!´þÿ!¶þÿ#·þÿ$·ÿÿ"¸ÿÿ!·þÿ"½þÿ"½þÿ!¹ÿÿ#¿ÿÿ!½ÿÿ¸ÿÿ$Åÿÿ&Ìÿÿ"Éÿÿ%Ïÿÿ%Ìÿÿ*Íÿÿ$¸ÿÿ™þÿ‘þÿ«þÿ%¿ÿÿ#·þÿ ´ÿÿ"®ùÿ'u°ÿ(ÿ'<}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ%ÿ8ÿM%ÿa2ÿx@ÿ“Rÿ©nÿ»…ÿÈ—HÿÔªrÿÝ»kÿãÀ;ÿèÂCÿé¦:ÿè¤>ÿíÆ`ÿëºVÿá–)ÿÏ~ÿ·w#ÿ°|*ÿ¬y1ÿ¢y=ÿ™}HÿŽ‚]ÿ‚Œuÿr“ÿ_—¨ÿM›¿ÿ9•Òÿ-“èÿ'™öÿ ˜üÿ–üÿ¬ýÿ²ÿÿ¢ÿÿ!¤ûÿšùÿŽüÿ¥þÿ"µþÿ®þÿ °þÿ!±ÿÿ³ÿÿ¯þÿ ±ÿÿ#¶ÿÿ#¹ÿÿ!¸ÿÿ »þÿ!»þÿ¶ÿÿ"Áÿÿ"Àÿÿ»ÿÿ$Æÿÿ$ÊÿÿÈÿÿ"Ìÿÿ&Îÿÿ+Íÿÿ&¼ÿÿ£þÿþÿ!±þÿ"¹þÿ!´þÿ!·ÿÿ"«ùÿ'n°ÿ+8pÿ)=}ÿ(<|ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ!ÿ,ÿ:ÿH"ÿV(ÿc.ÿq9 ÿ|Dÿ„Jÿ‰LÿLÿ’`*ÿ›‹[ÿšŠSÿ‘}ZÿŠdÿ‡Šoÿ€Žyÿt‹ˆÿj™ÿ`ž¨ÿQ¸ÿE Êÿ=©Üÿ0›âÿ ÚÿvÔÿ~Ýÿ‘óÿ“þÿ˜ÿÿ$²ÿÿ «þÿäÿk×ÿqëÿþÿ$¶ÿÿ%»ÿÿ"±þÿ#°þÿ#¶ÿÿ·þÿ¬ÿÿ «þÿ!¢öÿ!¢ûÿ"´ÿÿ ¼ÿÿ#½ÿÿ"¼ÿÿ!½þÿ$Âÿÿ%Äÿÿ$Çÿÿ%Ëÿÿ&Ïÿÿ(Óÿÿ,Øÿÿ)Ñÿÿ&Ëÿÿ&Äÿÿ&Áÿÿ%Áÿÿ!¸ÿÿ#¶þÿ"¸ÿÿ!¨ùÿ'a°ÿ.,oÿ)<ÿ'?}ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ! ÿ'ÿ-ÿ3ÿ5ÿ8ÿDOJÿV¡ÂÿU¦´ÿM·ÿGš¿ÿEœÇÿA—Îÿ9”Ôÿ3”Üÿ-œèÿ*¤ðÿ%¤öÿ!üÿøÿéÿtÑÿk¿ÿnÈÿ{Ýÿ%ôÿ$ ìÿ}ÖÿgÎÿl×ÿòÿ"´ÿÿ$Àþÿ!¸ÿÿ ·ÿÿ%¸ÿÿ&¼ÿÿ»ÿÿ¶ÿÿ!¤óÿh­ÿR˜ÿˆÙÿ!¹ÿÿ#Âÿÿ%Ãÿÿ!ºþÿ!»ÿÿ(Éÿÿ'Ìÿÿ$Êÿÿ+Õÿÿ0Þÿÿ-Ûÿÿ&Òÿÿ!Íÿÿ#Ëÿÿ"Æÿÿ&Äÿÿ$¼ÿÿ#³þÿ§ÿÿ!¢ùÿ'a±ÿ-/pÿ*7xÿ(6tÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿPhÿ3Ãúÿ1Áóÿ+¹ðÿ$°óÿ$¬ôÿ"øÿõÿ‚êÿ€íÿ›üÿ!©ÿÿ•ûÿˆôÿ‡åÿt¿ÿe²ÿ`·ÿf½ÿzÌÿwÎÿsÐÿŒèÿ!©÷ÿ#»þÿ"Áÿÿ»þÿ »þÿ!½ÿÿ"»ÿÿ#½ÿÿ¶ÿÿ´ÿÿ!£öÿb¨ÿ 6vÿjºÿ±ùÿ#Äÿÿ%Äÿÿ"»ÿÿ"»ÿÿ(Êÿÿ(Îÿÿ&Íÿÿ(Öÿÿ*Øÿÿ(Õÿÿ%Òÿÿ$Ìÿÿ$Çÿÿ!Áÿÿ ½ÿÿ ¸þÿªþÿ›ÿÿ •ùÿ%_°ÿ,1mÿ.)bÿ+$ZÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿKpÿ!¹ÿÿ§þÿ ´þÿ"¾ÿÿ¯ÿÿœÿÿŽýÿŠóÿ‡ñÿ™ýÿ!¡þÿ‰êÿvÔÿq¿ÿc¨ÿgÁÿwÞÿxÙÿnÑÿ{ãÿŸõÿ ¸ýÿ"Ãÿÿ&Éþÿ%Çÿÿ»ÿÿ ¾þÿ#Áþÿ"¾ÿÿ´ÿÿ¥þÿ°þÿ#¯þÿ‡èÿnÐÿ†àÿ ¬úÿ#½ÿÿ$Àÿÿ&Áÿÿ%¿ÿÿ%Ãÿÿ&Èÿÿ&Ïÿÿ$Òÿÿ#Ïÿÿ"Çþÿ%Ëÿÿ+Íÿÿ)Æÿÿ&Âÿÿ ¼ÿÿ°þÿ ¨ÿÿ¢ÿÿ‹÷ÿ%T¦ÿ,*eÿ-#Vÿ.GÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿT|ÿ!¹þÿ‘ûÿŸûÿ#¶ÿÿ¬þÿ›ýÿ’ýÿ’üÿŽöÿˆíÿ„êÿˆìÿ‡ãÿ{ÐÿtÏÿ|éÿ˜ýÿ£ùÿóÿ˜ûÿ'»ÿÿ%Äÿÿ ¾ÿÿ$Ãÿÿ&Äþÿ ¹þÿ­þÿ ¶þÿ$Áþÿ ¹þÿ¨þÿªþÿ%²ÿÿŸÿÿšýÿ ¤ýÿ «þÿ ´þÿ"ºÿÿ$½ÿÿ%½ÿÿ%Àÿÿ&Éÿÿ(Ðÿÿ&Òÿÿ'Ðÿÿ#Åÿÿ#Äÿÿ)Êÿÿ&Äÿÿ#¿þÿ#½þÿ!¶þÿ ©ÿÿ˜ýÿƒíÿ*J–ÿ1Lÿ/Lÿ.CÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_ˆÿ#Äþÿ¡ýÿ¥üÿ §þÿ¥þÿžþÿšÿÿ“ÿÿ‰óÿxÜÿrÓÿ~âÿ’ôÿ˜øÿ–øÿ–ýÿ¨ÿÿ&¼ÿÿ#°ÿÿ!©þÿ%ºþÿ$Áþÿ"¿ÿÿ"¾ÿÿ#¼þÿ ´þÿ«þÿ®þÿ"´þÿ%½þÿ#´þÿ¦þÿ¤þÿ þÿ ªÿÿ"²ÿÿ"°þÿ#´þÿ#¸ÿÿ$ºÿÿ%½ÿÿ#¼ÿÿ%Åÿÿ&Ìÿÿ Äþÿ#Æÿÿ'Ëÿÿ(Æÿÿ%Áÿÿ#¿ÿÿ´þÿ¯þÿ"¶þÿ#«þÿþÿväÿ(7ÿ3@ÿ-Qÿ,PÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿb‡ÿ&Ðþÿ"µÿÿ"°ÿÿ¥þÿþÿŸþÿ—ùÿ‹÷ÿöÿƒéÿ~âÿ„ëÿ–ùÿ¤ÿÿ§ÿÿ¬þÿ!²þÿ'ºþÿ&·þÿ©þÿ¨þÿ¸þÿ"Àþÿ!ºþÿ ®þÿ¦þÿ!­þÿ ¬þÿ¡þÿ ªþÿ!ªþÿŸþÿœþÿ£þÿ!±þÿ!¶þÿ ¯þÿ ¬þÿ"±þÿ&¹ÿÿ(¿ÿÿ%¿ÿÿ$¾ÿÿ'Çÿÿ ½ÿÿ¹ÿÿ"¼ÿÿ%¿þÿ#·þÿ ´þÿ!µþÿ¦þÿ¤þÿ!«þÿ§ÿÿŠïÿ(A’ÿ2Jÿ-#\ÿ*%_ÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ\„ÿ$Êþÿ"´þÿ ¬ýÿ§þÿ£þÿžþÿ÷ÿ‹öÿ’úÿƒíÿ‡ñÿ™üÿšþÿ¦ÿÿ ²þÿ ·þÿ²þÿ"°þÿ#²þÿ«þÿ­þÿ·þÿ³þÿ±þÿ!°þÿ¤þÿŸþÿ¥þÿ ¦þÿ  þÿŸþÿ™þÿ þÿ"­þÿ©þÿ¦þÿ §þÿ ªþÿ ¬þÿ#³þÿ%»þÿ#¼þÿ%¼ÿÿ(Äÿÿ'Ãÿÿ%¿ÿÿ ¶ÿÿ«þÿ°þÿ ±þÿ#·þÿ °þÿ¦þÿªþÿ³ÿÿ§øÿ+]¬ÿ1]ÿ,,iÿ*0nÿL`~ÿMb€ÿ>Ngÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ N}ÿ¯þÿœþÿ¢ÿÿ¤ÿÿ"¬þÿ!¬þÿüÿ–ýÿ”üÿŒöÿ–úÿŸÿÿžþÿ©þÿ ´þÿµþÿ®þÿ¨þÿŸþÿ¤þÿ µþÿ!ºþÿ µþÿ¯þÿ¦þÿ£þÿ¦þÿ ©þÿ!¨þÿ¡þÿ ¢þÿ£þÿ¥þÿ!ªþÿ"ªþÿ!©þÿ#¬þÿ#±þÿ"²þÿ"±þÿ$µþÿ%¹þÿ%¹þÿ"´þÿ'¾þÿ'¿þÿ$¸þÿ²þÿ!²þÿ!´þÿ¯þÿ#¶þÿ#±þÿ£þÿ²ÿÿ¯úÿ(i±ÿ1#hÿ-.sÿ+3vÿL`~ÿMb€ÿ>NgÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿLyÿªþÿŠüÿùÿ þÿ#±ÿÿ#¯þÿŸþÿ”þÿ”þÿ  ýÿ!¥þÿ¡þÿ «þÿ!´þÿ­þÿ²þÿ"¶þÿ£ýÿŸýÿ°þÿ!¸þÿ!¹þÿ ¶þÿ¨þÿ™þÿœþÿ ªþÿ!¯þÿ ¦þÿ ¢þÿ"ªþÿ$²þÿ"¦þÿ˜ýÿ üÿ$±þÿ#°þÿ"¦þÿ¦þÿ «þÿ!¯þÿ%¸þÿ&½þÿ¬þÿ"®þÿ#µþÿ#¶þÿ!²þÿ!°þÿ"´þÿ!°þÿ ³þÿ!±þÿ¯þÿ¶ÿÿ!´ùÿ)q±ÿ1%mÿ/(vÿ-,vÿL`~ÿMb€ÿ>NeÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿPzÿ$»þÿõÿìÿ˜ÿÿ§ÿÿ"±ÿÿ!­ÿÿ›ÿÿ”ÿÿ¡ÿÿ §ÿÿ¡ÿÿ¦ÿÿ«ÿÿ¤ÿÿ¥ÿÿ©ÿÿ˜ÿÿšÿÿ²ÿÿ#¿ÿÿ$Áÿÿµÿÿ£ÿÿ£ÿÿ¨ÿÿ¬ÿÿ°ÿÿ ®ÿÿ «ÿÿ©ÿÿ!±ÿÿ"±ÿÿ›ÿÿ•ÿÿ£ÿÿ¡ÿÿ—ÿÿ¡ÿÿ!®ÿÿ#¶ÿÿ%·ÿÿ ªÿÿ¡ÿÿ ÿÿ"±ÿÿ$¸ÿÿ µÿÿ"µÿÿµÿÿ"¹ÿÿ!¶ÿÿ±ÿÿ!·ÿÿ"¼ÿÿ"¹ùÿ*v²ÿ/0rÿ,8}ÿ+9|ÿL`~ÿMb€ÿ>NeÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJxÿ&·ÿÿ!¡üÿ˜ûÿ ™þÿúÿ¢ýÿ"®ÿÿ›ÿÿ–ÿÿšÿÿ’ûÿúÿ—ÿÿÿÿ“÷ÿŽöÿ—üÿ¢ÿÿ›þÿ£þÿ"¶ÿÿ!±ÿÿ®ÿÿ ´ÿÿ!µÿÿ°ÿÿ ±ÿÿ"´ÿÿ"²ÿÿ ¨ÿÿ ÿÿ¢ÿÿ©ÿÿ"­ÿÿ!°ÿÿ ¯ÿÿ þÿûÿžþÿ"²ÿÿ!¯ÿÿ¢þÿ’þÿ“ÿÿ ©ÿÿ#¶ÿÿ"²ÿÿ¬ÿÿ ®ÿÿ­ÿÿ!³ÿÿ"¶ÿÿ¬ÿÿ«ÿÿ ¸ÿÿ!²üÿ&w°ÿ,Drÿ+Jÿ)H~ÿL`~ÿL`~ÿI\yÿ?Nhÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ngÿ>Ogÿ>Lbÿ4Feÿ)Sšÿ-N™ÿ,E–ÿ,Dÿ+B–ÿ,Jœÿ,Všÿ)U–ÿ,A”ÿ-<’ÿ+:ÿ,8Œÿ*F•ÿ'N›ÿ+>‹ÿ./}ÿ1.€ÿ/?Œÿ)V˜ÿ%g˜ÿ*d—ÿ,W—ÿ,X—ÿ*d—ÿ*j—ÿ)d—ÿ+^—ÿ+]—ÿ+`—ÿ+Z—ÿ,O–ÿ+L–ÿ*Q—ÿ+X—ÿ,V—ÿ,V—ÿ'd˜ÿ%_—ÿ,L—ÿ.K—ÿ+Q—ÿ*T—ÿ&Z—ÿ&\—ÿ,Z—ÿ-Y—ÿ*^—ÿ)\—ÿ*]—ÿ'c—ÿ)d—ÿ)f—ÿ)c—ÿ*b—ÿ,d˜ÿ)f˜ÿ)^Šÿ,P|ÿ,O€ÿ+NÿL`~ÿL`~ÿL`~ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMb€ÿMcÿM_{ÿ=Mjÿ'K~ÿ)Eÿ/.xÿ/*oÿ-/pÿ0$cÿ0+nÿ-;€ÿ00~ÿ01~ÿ,7}ÿ+5xÿ./uÿ.0zÿ,2yÿ./tÿ1'nÿ2)tÿ-C}ÿ)Wÿ,N~ÿ.J~ÿ.H~ÿ0F~ÿ/J~ÿ.J~ÿ,I~ÿ-E~ÿ-F~ÿ,I~ÿ->}ÿ06}ÿ0:~ÿ.@ÿ-A~ÿ/9~ÿ*K€ÿ)K}ÿ00wÿ10zÿ/<~ÿ.>~ÿ,E~ÿ)O~ÿ(Q~ÿ-D~ÿ-G~ÿ(O~ÿ-G~ÿ*R~ÿ*R~ÿ+Q~ÿ)T~ÿ*T~ÿ*U~ÿ(Z~ÿ)[€ÿ*Wÿ)Vÿ(VÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿL`~ÿLaÿL]xÿ?Biÿ*9}ÿ+>wÿ/.sÿ-4{ÿ-'hÿ0Iÿ1Sÿ0"eÿ1%jÿ.3zÿ,Bƒÿ-;|ÿ/.pÿ./qÿ+9xÿ*Aÿ+=ÿ/2}ÿ/6}ÿ,F€ÿ.G€ÿ-O€ÿ,O€ÿ0?€ÿ/A€ÿ-J€ÿ+M€ÿ*N€ÿ+K€ÿ,F€ÿ.@€ÿ0;€ÿ25|ÿ25zÿ.Bÿ+Eÿ+A€ÿ,<ÿ,;~ÿ)F€ÿ,E€ÿ-C€ÿ,I€ÿ,J€ÿ+O€ÿ+Q€ÿ-G€ÿ-E€ÿ-F€ÿ+K€ÿ(T€ÿ)V€ÿ*P€ÿ-H€ÿ,R€ÿ.Y€ÿ,W€ÿ(Xÿ)Wÿ(X€ÿdxx-rebirth-0.58.1-d1x/arch/win32/d1x-rebirth.rc000066400000000000000000000030141217717257200211060ustar00rootroot00000000000000// Microsoft Visual C++ generated resource script. // #include "include/resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" IDI_DXX_ICON ICON "d1x-rebirth.ico" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "include/resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "IDI_DXX_ICON ICON ""d1x-rebirth.ico""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED dxx-rebirth-0.58.1-d1x/arch/win32/include/000077500000000000000000000000001217717257200200545ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/arch/win32/include/resource.h000066400000000000000000000007521217717257200220600ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by d1x-rebirth.rc // #define IDI_DXX_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 147 #define _APS_NEXT_COMMAND_VALUE 40028 #define _APS_NEXT_CONTROL_VALUE 1009 #define _APS_NEXT_SYMED_VALUE 102 #endif #endif dxx-rebirth-0.58.1-d1x/arch/win32/messagebox.c000066400000000000000000000017101217717257200207310ustar00rootroot00000000000000/* * messagebox.c * d1x-rebirth * * Display an error or warning messagebox using the OS's window server. * */ #include #include "window.h" #include "event.h" #include "messagebox.h" void display_win32_alert(char *message, int error) { d_event event; window *wind; int fullscreen; // Handle Descent's windows properly if ((wind = window_get_front())) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_DEACTIVATED); if (grd_curscreen && (fullscreen = gr_check_fullscreen())) gr_toggle_fullscreen(); MessageBox(NULL, message, error?"Sorry, a critical error has occurred.":"Attention!", error?MB_OK|MB_ICONERROR:MB_OK|MB_ICONWARNING); if ((wind = window_get_front())) WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED); if (grd_curscreen && !error && fullscreen) gr_toggle_fullscreen(); } void msgbox_warning(char *message) { display_win32_alert(message, 0); } void msgbox_error(const char *message) { display_win32_alert(message, 1); } dxx-rebirth-0.58.1-d1x/d1x-Info.plist000066400000000000000000000014311217717257200172130ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable d1x CFBundleIconFile d1x-rebirth CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature DCNT CFBundleVersion 0.57.3 CSResourcesFileMapped LSPrefersCarbon NSMainNibFile MainMenu NSPrincipalClass NSApplication dxx-rebirth-0.58.1-d1x/d1x-rebirth.bmp000066400000000000000000000040661217717257200174110ustar00rootroot00000000000000BM66(     " *>3G!L%.N[..]o:.,d0)uˆJ-2s/2y†M -7{+;q+;/=z+>|šY'B{‘W9Jb)DŽ+I}'J-M|(G–«g)O}§hša¤e'U€,V{›h(X~›g*)Qœ¤j"*\|§oJ\ušl.¢o&'b|¿x¦tI_€„jJ([œ­t˜o6žp3Kc~Œo@¢u+¨t.¢s7+aœ­{&ǃ'g´{*­y4¨{3¬€*ŒzM³€.»ƒ"²}:º€2Ä-°‚<·„4z{hXNt›½‰;¼†Fȇ?Î+À0 rÏÆ‹=Þ“€„oÁ@i‰Ð;Í–&֘Ɠ9É—+ËGΔ=Û™.€m’jÊ•JДMÝ•FÓ›6V‡¤ì¡О0ƒÏÚ˜GÏœDÖœH€èÖšS+„ÞÌžQÖ¤?…ëd”Ù¨2çª'î©+ˆãY”¦Ü¡Nà¨7ߥEé´Ý [ã¢S0Œàá±*ݪGí¤Yï§OìØªRâ°?Žôõ9—Òë©\ìµ6LœÁê±Eàªbç·4'”ëî®P2—àMŸ¾—ìê°S ”ÿÝ®cû°Uã¸Eñ¶G–üò¯cÈ´dî³[™ÿö¶P›ûP¨¿à¶bþ·U÷¶^óÄ2žÿìÃ<ÿ¶bÖ·nòÁD! ú£ñ#Ÿÿ£þé¼fçºsä¼nø¼hæ¿e§ý,«ëõÌ:ûÂZ ªÿªÿ÷Ä`®ÿöÌN ®þÿÄkòÏMôË_öÇsýÔGµÿ%´þìËoºÿ¹ýúÙGìÉ‚êË}&¼ô»ÿú×Wõʇ¿ÿ"ÀÿíцíÏŽýÙh%ÄþÆÿÿØuøÚyøÔŽÿÙËÿýßtþÝ‚!ÐþùÛ›ûÞ”üáŒ&ÕþöÝ¢ûå—ýæ¡þô€þò”ÿï°ÿî·ÿôµÿñÃýø­ùîÒÿÿ¬þû»þÿÈÿý×ÿÿò<2>GJJ-dxx-rebirth-0.58.1-d1x/d1x-rebirth.desktop000066400000000000000000000003441217717257200202770ustar00rootroot00000000000000[Desktop Entry] Name=Descent 1 Version=1.0 Comment=DXX-Rebirth source port of Descent: First Strike from 1995... Exec=d1x-rebirth Icon=d1x-rebirth Terminal=false Type=Application Categories=Game;ActionGame; StartupNotify=false dxx-rebirth-0.58.1-d1x/d1x-rebirth.xcodeproj/000077500000000000000000000000001217717257200206775ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/d1x-rebirth.xcodeproj/project.pbxproj000077500000000000000000005665431217717257200240010ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXBuildFile section */ 179E6E9E11F37B3400175C54 /* hmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 179E6E9D11F37B3400175C54 /* hmp.c */; }; 179E6E9F11F37B3400175C54 /* hmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 179E6E9D11F37B3400175C54 /* hmp.c */; }; 17A707EB10C1B5FA002D1680 /* SDL_mixer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB92BEC40CDD6B4B0045A32C /* SDL_mixer.framework */; }; 17DFA6B110C1A29500674D11 /* net_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 17DFA6AF10C1A29500674D11 /* net_udp.c */; }; 6710AAFF066B2D6100DB0F68 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6710AAFE066B2D6100DB0F68 /* SDL.framework */; }; 6710AB00066B2D6100DB0F68 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6710AAFE066B2D6100DB0F68 /* SDL.framework */; }; 6710AB69066B2E0400DB0F68 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6710AB68066B2E0400DB0F68 /* OpenGL.framework */; }; 675ED149066B198A00E42AA7 /* d1x-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 675ED123066B196700E42AA7 /* d1x-Info.plist */; }; 676032E0066B399A008A67A3 /* multi.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032DC066B399A008A67A3 /* multi.c */; }; 676032E1066B399A008A67A3 /* multibot.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032DD066B399A008A67A3 /* multibot.c */; }; 676032E4066B399A008A67A3 /* multi.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032DC066B399A008A67A3 /* multi.c */; }; 676032E5066B399A008A67A3 /* multibot.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032DD066B399A008A67A3 /* multibot.c */; }; 676032FA066B39CE008A67A3 /* kmatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032F9066B39CE008A67A3 /* kmatrix.c */; }; 676032FB066B39CE008A67A3 /* kmatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 676032F9066B39CE008A67A3 /* kmatrix.c */; }; 6766BAC20668B3A000A6052D /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 676AC1C20668A938007173EB /* u_mem.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B4490F066880A300DF26D8 /* u_mem.h */; }; 676AC1C40668A938007173EB /* gr.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B44914066880C400DF26D8 /* gr.h */; }; 676AC1C50668A938007173EB /* grdef.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B44915066880C400DF26D8 /* grdef.h */; }; 676AC1C70668A938007173EB /* byteswap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CE4F0668852C00056A5A /* byteswap.h */; }; 676AC1C80668A938007173EB /* rle.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CE500668852C00056A5A /* rle.h */; }; 676AC1CE0668A938007173EB /* fix.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF420668881F00056A5A /* fix.h */; }; 676AC1CF0668A938007173EB /* palette.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF4E0668883900056A5A /* palette.h */; }; 676AC1D00668A938007173EB /* pcx.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF620668885500056A5A /* pcx.h */; }; 676AC1D10668A938007173EB /* 3d.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF8D066888DD00056A5A /* 3d.h */; }; 676AC1D20668A938007173EB /* texmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CFB10668891200056A5A /* texmap.h */; }; 676AC1D70668A938007173EB /* args.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D00B066889CD00056A5A /* args.h */; }; 676AC1D90668A938007173EB /* vecmat.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D026066889F100056A5A /* vecmat.h */; }; 676AC1DA0668A938007173EB /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D04B06688A2E00056A5A /* timer.h */; }; 676AC1DE0668A938007173EB /* maths.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D08F06688A9C00056A5A /* maths.h */; }; 676AC1E00668A938007173EB /* strutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D0A306688AB900056A5A /* strutil.h */; }; 676AC1E10668A938007173EB /* iff.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D0BD06688AE800056A5A /* iff.h */; }; 676AC1E50668A938007173EB /* strio.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D1550668903B00056A5A /* strio.h */; }; 676AC1EC0668A938007173EB /* 2dsline.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44139066878B300DF26D8 /* 2dsline.c */; }; 676AC1ED0668A938007173EB /* bitblt.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413A066878B300DF26D8 /* bitblt.c */; }; 676AC1EE0668A938007173EB /* bitmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413B066878B300DF26D8 /* bitmap.c */; }; 676AC1EF0668A938007173EB /* box.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413D066878B300DF26D8 /* box.c */; }; 676AC1F00668A938007173EB /* canvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413E066878B300DF26D8 /* canvas.c */; }; 676AC1F10668A938007173EB /* circle.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413F066878B300DF26D8 /* circle.c */; }; 676AC1F20668A938007173EB /* disc.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44141066878B300DF26D8 /* disc.c */; }; 676AC1F30668A938007173EB /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44142066878B300DF26D8 /* font.c */; }; 676AC1F40668A938007173EB /* gpixel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44143066878B300DF26D8 /* gpixel.c */; }; 676AC1F60668A938007173EB /* line.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44145066878B300DF26D8 /* line.c */; }; 676AC1F70668A938007173EB /* palette.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44148066878B300DF26D8 /* palette.c */; }; 676AC1F80668A938007173EB /* pcx.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44149066878B300DF26D8 /* pcx.c */; }; 676AC1F90668A938007173EB /* pixel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414A066878B300DF26D8 /* pixel.c */; }; 676AC1FA0668A938007173EB /* poly.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414B066878B300DF26D8 /* poly.c */; }; 676AC1FB0668A938007173EB /* rect.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414C066878B300DF26D8 /* rect.c */; }; 676AC1FC0668A938007173EB /* rle.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414D066878B300DF26D8 /* rle.c */; }; 676AC1FD0668A938007173EB /* scalec.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44151066878B300DF26D8 /* scalec.c */; }; 676AC1FF0668A938007173EB /* clipper.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441760668792300DF26D8 /* clipper.c */; }; 676AC2000668A938007173EB /* draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441780668792300DF26D8 /* draw.c */; }; 676AC2010668A938007173EB /* globvars.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441790668792300DF26D8 /* globvars.c */; }; 676AC2020668A938007173EB /* instance.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417B0668792300DF26D8 /* instance.c */; }; 676AC2030668A938007173EB /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417D0668792300DF26D8 /* interp.c */; }; 676AC2040668A938007173EB /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417F0668792300DF26D8 /* matrix.c */; }; 676AC2050668A938007173EB /* points.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441800668792300DF26D8 /* points.c */; }; 676AC2060668A938007173EB /* rod.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441810668792300DF26D8 /* rod.c */; }; 676AC2070668A938007173EB /* setup.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441820668792300DF26D8 /* setup.c */; }; 676AC20A0668A938007173EB /* digi.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D306687A0200DF26D8 /* digi.c */; }; 676AC20B0668A938007173EB /* event.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D406687A0200DF26D8 /* event.c */; }; 676AC20C0668A938007173EB /* gr.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D506687A0200DF26D8 /* gr.c */; }; 676AC20E0668A938007173EB /* joy.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D706687A0200DF26D8 /* joy.c */; }; 676AC2100668A938007173EB /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D906687A0200DF26D8 /* key.c */; }; 676AC2110668A938007173EB /* mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441DB06687A0200DF26D8 /* mouse.c */; }; 676AC2130668A938007173EB /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441DD06687A0200DF26D8 /* timer.c */; }; 676AC2150668A938007173EB /* iff.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4420006687A9E00DF26D8 /* iff.c */; }; 676AC2160668A938007173EB /* ai.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446CF06687CF400DF26D8 /* ai.c */; }; 676AC2180668A938007173EB /* aipath.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D206687CF400DF26D8 /* aipath.c */; }; 676AC2190668A938007173EB /* automap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D406687CF400DF26D8 /* automap.c */; }; 676AC21A0668A938007173EB /* bm.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D606687CF400DF26D8 /* bm.c */; }; 676AC21C0668A938007173EB /* cntrlcen.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446DB06687CF400DF26D8 /* cntrlcen.c */; }; 676AC21D0668A938007173EB /* collide.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446DD06687CF400DF26D8 /* collide.c */; }; 676AC21E0668A938007173EB /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E006687CF400DF26D8 /* config.c */; }; 676AC21F0668A938007173EB /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E206687CF400DF26D8 /* console.c */; }; 676AC2200668A938007173EB /* controls.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E306687CF400DF26D8 /* controls.c */; }; 676AC2210668A938007173EB /* credits.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E506687CF400DF26D8 /* credits.c */; }; 676AC2230668A938007173EB /* effects.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446F706687CF400DF26D8 /* effects.c */; }; 676AC2240668A938007173EB /* endlevel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446F906687CF400DF26D8 /* endlevel.c */; }; 676AC2260668A938007173EB /* fireball.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446FD06687CF400DF26D8 /* fireball.c */; }; 676AC2270668A938007173EB /* fuelcen.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446FF06687CF400DF26D8 /* fuelcen.c */; }; 676AC2280668A938007173EB /* fvi.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470106687CF400DF26D8 /* fvi.c */; }; 676AC2290668A938007173EB /* game.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470406687CF400DF26D8 /* game.c */; }; 676AC22B0668A938007173EB /* gamefont.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470706687CF400DF26D8 /* gamefont.c */; }; 676AC22C0668A938007173EB /* gamemine.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470906687CF400DF26D8 /* gamemine.c */; }; 676AC22F0668A938007173EB /* gamesave.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470E06687CF400DF26D8 /* gamesave.c */; }; 676AC2300668A938007173EB /* gameseg.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471006687CF400DF26D8 /* gameseg.c */; }; 676AC2310668A938007173EB /* gameseq.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471206687CF400DF26D8 /* gameseq.c */; }; 676AC2320668A938007173EB /* gauges.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471506687CF400DF26D8 /* gauges.c */; }; 676AC2330668A938007173EB /* hostage.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471706687CF400DF26D8 /* hostage.c */; }; 676AC2340668A938007173EB /* hud.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471906687CF400DF26D8 /* hud.c */; }; 676AC2350668A938007173EB /* inferno.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471B06687CF400DF26D8 /* inferno.c */; }; 676AC2360668A938007173EB /* kconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472006687CF400DF26D8 /* kconfig.c */; }; 676AC2380668A938007173EB /* laser.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472506687CF400DF26D8 /* laser.c */; }; 676AC2390668A938007173EB /* lighting.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472706687CF400DF26D8 /* lighting.c */; }; 676AC23A0668A938007173EB /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472B06687CF400DF26D8 /* menu.c */; }; 676AC23B0668A938007173EB /* mglobal.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472D06687CF400DF26D8 /* mglobal.c */; }; 676AC23C0668A938007173EB /* mission.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472E06687CF400DF26D8 /* mission.c */; }; 676AC23D0668A938007173EB /* morph.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473106687CF400DF26D8 /* morph.c */; }; 676AC23F0668A938007173EB /* newdemo.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473D06687CF400DF26D8 /* newdemo.c */; }; 676AC2400668A938007173EB /* newmenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473F06687CF400DF26D8 /* newmenu.c */; }; 676AC2410668A938007173EB /* object.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4474106687CF400DF26D8 /* object.c */; }; 676AC2420668A938007173EB /* paging.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475906687CF400DF26D8 /* paging.c */; }; 676AC2430668A938007173EB /* physics.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475B06687CF400DF26D8 /* physics.c */; }; 676AC2440668A938007173EB /* piggy.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475D06687CF400DF26D8 /* piggy.c */; }; 676AC2460668A938007173EB /* playsave.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476106687CF400DF26D8 /* playsave.c */; }; 676AC2470668A938007173EB /* polyobj.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476306687CF400DF26D8 /* polyobj.c */; }; 676AC2480668A938007173EB /* powerup.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476506687CF400DF26D8 /* powerup.c */; }; 676AC2490668A938007173EB /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476706687CF400DF26D8 /* render.c */; }; 676AC24A0668A938007173EB /* robot.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476A06687CF400DF26D8 /* robot.c */; }; 676AC24B0668A938007173EB /* scores.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476C06687CF400DF26D8 /* scores.c */; }; 676AC24D0668A938007173EB /* slew.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477206687CF400DF26D8 /* slew.c */; }; 676AC24E0668A938007173EB /* songs.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477406687CF400DF26D8 /* songs.c */; }; 676AC24F0668A938007173EB /* state.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477706687CF400DF26D8 /* state.c */; }; 676AC2500668A938007173EB /* switch.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477906687CF400DF26D8 /* switch.c */; }; 676AC2510668A938007173EB /* terrain.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477B06687CF400DF26D8 /* terrain.c */; }; 676AC2520668A938007173EB /* texmerge.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477D06687CF400DF26D8 /* texmerge.c */; }; 676AC2530668A938007173EB /* text.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477F06687CF500DF26D8 /* text.c */; }; 676AC2540668A938007173EB /* titles.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478206687CF500DF26D8 /* titles.c */; }; 676AC2550668A938007173EB /* vclip.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478406687CF500DF26D8 /* vclip.c */; }; 676AC2560668A938007173EB /* wall.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478706687CF500DF26D8 /* wall.c */; }; 676AC2570668A938007173EB /* weapon.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478906687CF500DF26D8 /* weapon.c */; }; 676AC2580668A938007173EB /* fixc.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484B06687DCE00DF26D8 /* fixc.c */; }; 676AC2590668A938007173EB /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484D06687DCE00DF26D8 /* rand.c */; }; 676AC25A0668A938007173EB /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484E06687DCE00DF26D8 /* tables.c */; }; 676AC25B0668A938007173EB /* vecmat.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484F06687DCE00DF26D8 /* vecmat.c */; }; 676AC25C0668A938007173EB /* mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4485E06687DFB00DF26D8 /* mem.c */; }; 676AC25F0668A938007173EB /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4486A06687E1000DF26D8 /* error.c */; }; 676AC2610668A938007173EB /* strio.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4487206687E1000DF26D8 /* strio.c */; }; 676AC2620668A938007173EB /* strutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4487306687E1000DF26D8 /* strutil.c */; }; 676AC2630668A938007173EB /* ntmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4488806687E5E00DF26D8 /* ntmap.c */; }; 676AC2640668A938007173EB /* scanline.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4488906687E5E00DF26D8 /* scanline.c */; }; 676AC2650668A938007173EB /* tmapflat.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4489206687E5E00DF26D8 /* tmapflat.c */; }; 676AC26C0668A938007173EB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 676AC2770668A939007173EB /* 3d.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF8D066888DD00056A5A /* 3d.h */; }; 676AC2780668A939007173EB /* args.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D00B066889CD00056A5A /* args.h */; }; 676AC2790668A939007173EB /* byteswap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CE4F0668852C00056A5A /* byteswap.h */; }; 676AC2800668A939007173EB /* fix.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF420668881F00056A5A /* fix.h */; }; 676AC2810668A939007173EB /* gr.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B44914066880C400DF26D8 /* gr.h */; }; 676AC2820668A939007173EB /* grdef.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B44915066880C400DF26D8 /* grdef.h */; }; 676AC2850668A939007173EB /* iff.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D0BD06688AE800056A5A /* iff.h */; }; 676AC2890668A939007173EB /* maths.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D08F06688A9C00056A5A /* maths.h */; }; 676AC28C0668A939007173EB /* pcx.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF620668885500056A5A /* pcx.h */; }; 676AC28D0668A939007173EB /* palette.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CF4E0668883900056A5A /* palette.h */; }; 676AC2900668A939007173EB /* rle.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CE500668852C00056A5A /* rle.h */; }; 676AC2910668A939007173EB /* strio.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D1550668903B00056A5A /* strio.h */; }; 676AC2920668A939007173EB /* strutil.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D0A306688AB900056A5A /* strutil.h */; }; 676AC2930668A939007173EB /* texmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791CFB10668891200056A5A /* texmap.h */; }; 676AC2940668A939007173EB /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D04B06688A2E00056A5A /* timer.h */; }; 676AC2960668A939007173EB /* u_mem.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B4490F066880A300DF26D8 /* u_mem.h */; }; 676AC2970668A939007173EB /* vecmat.h in Headers */ = {isa = PBXBuildFile; fileRef = 6791D026066889F100056A5A /* vecmat.h */; }; 676AC29C0668A939007173EB /* 2dsline.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44139066878B300DF26D8 /* 2dsline.c */; }; 676AC29D0668A939007173EB /* bitblt.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413A066878B300DF26D8 /* bitblt.c */; }; 676AC29E0668A939007173EB /* bitmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413B066878B300DF26D8 /* bitmap.c */; }; 676AC29F0668A939007173EB /* box.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413D066878B300DF26D8 /* box.c */; }; 676AC2A00668A939007173EB /* canvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413E066878B300DF26D8 /* canvas.c */; }; 676AC2A10668A939007173EB /* circle.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4413F066878B300DF26D8 /* circle.c */; }; 676AC2A20668A939007173EB /* disc.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44141066878B300DF26D8 /* disc.c */; }; 676AC2A30668A939007173EB /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44142066878B300DF26D8 /* font.c */; }; 676AC2A40668A939007173EB /* gpixel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44143066878B300DF26D8 /* gpixel.c */; }; 676AC2A60668A939007173EB /* line.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44145066878B300DF26D8 /* line.c */; }; 676AC2A70668A939007173EB /* palette.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44148066878B300DF26D8 /* palette.c */; }; 676AC2A80668A939007173EB /* pcx.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44149066878B300DF26D8 /* pcx.c */; }; 676AC2A90668A939007173EB /* pixel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414A066878B300DF26D8 /* pixel.c */; }; 676AC2AA0668A939007173EB /* poly.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414B066878B300DF26D8 /* poly.c */; }; 676AC2AB0668A939007173EB /* rect.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414C066878B300DF26D8 /* rect.c */; }; 676AC2AC0668A939007173EB /* rle.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4414D066878B300DF26D8 /* rle.c */; }; 676AC2AD0668A939007173EB /* scalec.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B44151066878B300DF26D8 /* scalec.c */; }; 676AC2AF0668A939007173EB /* clipper.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441760668792300DF26D8 /* clipper.c */; }; 676AC2B00668A939007173EB /* draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441780668792300DF26D8 /* draw.c */; }; 676AC2B10668A939007173EB /* globvars.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441790668792300DF26D8 /* globvars.c */; }; 676AC2B20668A939007173EB /* instance.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417B0668792300DF26D8 /* instance.c */; }; 676AC2B30668A939007173EB /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417D0668792300DF26D8 /* interp.c */; }; 676AC2B40668A939007173EB /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4417F0668792300DF26D8 /* matrix.c */; }; 676AC2B50668A939007173EB /* points.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441800668792300DF26D8 /* points.c */; }; 676AC2B60668A939007173EB /* rod.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441810668792300DF26D8 /* rod.c */; }; 676AC2B70668A939007173EB /* setup.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441820668792300DF26D8 /* setup.c */; }; 676AC2BA0668A939007173EB /* digi.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D306687A0200DF26D8 /* digi.c */; }; 676AC2BB0668A939007173EB /* event.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D406687A0200DF26D8 /* event.c */; }; 676AC2BD0668A939007173EB /* joy.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D706687A0200DF26D8 /* joy.c */; }; 676AC2BF0668A939007173EB /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441D906687A0200DF26D8 /* key.c */; }; 676AC2C00668A939007173EB /* mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441DB06687A0200DF26D8 /* mouse.c */; }; 676AC2C20668A939007173EB /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B441DD06687A0200DF26D8 /* timer.c */; }; 676AC2C30668A939007173EB /* gr.c in Sources */ = {isa = PBXBuildFile; fileRef = 676AC04E0668A814007173EB /* gr.c */; }; 676AC2C40668A939007173EB /* ogl.c in Sources */ = {isa = PBXBuildFile; fileRef = 676AC0510668A814007173EB /* ogl.c */; }; 676AC2C70668A939007173EB /* iff.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4420006687A9E00DF26D8 /* iff.c */; }; 676AC2CD0668A939007173EB /* ai.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446CF06687CF400DF26D8 /* ai.c */; }; 676AC2CF0668A939007173EB /* aipath.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D206687CF400DF26D8 /* aipath.c */; }; 676AC2D00668A939007173EB /* automap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D406687CF400DF26D8 /* automap.c */; }; 676AC2D10668A939007173EB /* bm.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446D606687CF400DF26D8 /* bm.c */; }; 676AC2D30668A939007173EB /* cntrlcen.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446DB06687CF400DF26D8 /* cntrlcen.c */; }; 676AC2D40668A939007173EB /* collide.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446DD06687CF400DF26D8 /* collide.c */; }; 676AC2D50668A939007173EB /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E006687CF400DF26D8 /* config.c */; }; 676AC2D60668A939007173EB /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E206687CF400DF26D8 /* console.c */; }; 676AC2D70668A939007173EB /* controls.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E306687CF400DF26D8 /* controls.c */; }; 676AC2D80668A939007173EB /* credits.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446E506687CF400DF26D8 /* credits.c */; }; 676AC2DA0668A939007173EB /* effects.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446F706687CF400DF26D8 /* effects.c */; }; 676AC2DB0668A939007173EB /* endlevel.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446F906687CF400DF26D8 /* endlevel.c */; }; 676AC2DD0668A939007173EB /* fireball.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446FD06687CF400DF26D8 /* fireball.c */; }; 676AC2DE0668A939007173EB /* fuelcen.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B446FF06687CF400DF26D8 /* fuelcen.c */; }; 676AC2DF0668A939007173EB /* fvi.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470106687CF400DF26D8 /* fvi.c */; }; 676AC2E00668A939007173EB /* game.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470406687CF400DF26D8 /* game.c */; }; 676AC2E20668A939007173EB /* gamefont.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470706687CF400DF26D8 /* gamefont.c */; }; 676AC2E30668A939007173EB /* gamemine.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470906687CF400DF26D8 /* gamemine.c */; }; 676AC2E60668A939007173EB /* gamesave.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4470E06687CF400DF26D8 /* gamesave.c */; }; 676AC2E70668A939007173EB /* gameseg.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471006687CF400DF26D8 /* gameseg.c */; }; 676AC2E80668A939007173EB /* gameseq.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471206687CF400DF26D8 /* gameseq.c */; }; 676AC2E90668A939007173EB /* gauges.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471506687CF400DF26D8 /* gauges.c */; }; 676AC2EA0668A939007173EB /* hostage.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471706687CF400DF26D8 /* hostage.c */; }; 676AC2EB0668A939007173EB /* hud.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471906687CF400DF26D8 /* hud.c */; }; 676AC2EC0668A939007173EB /* inferno.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4471B06687CF400DF26D8 /* inferno.c */; }; 676AC2ED0668A939007173EB /* kconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472006687CF400DF26D8 /* kconfig.c */; }; 676AC2EF0668A939007173EB /* laser.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472506687CF400DF26D8 /* laser.c */; }; 676AC2F00668A939007173EB /* lighting.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472706687CF400DF26D8 /* lighting.c */; }; 676AC2F10668A939007173EB /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472B06687CF400DF26D8 /* menu.c */; }; 676AC2F20668A939007173EB /* mglobal.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472D06687CF400DF26D8 /* mglobal.c */; }; 676AC2F30668A939007173EB /* mission.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4472E06687CF400DF26D8 /* mission.c */; }; 676AC2F40668A939007173EB /* morph.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473106687CF400DF26D8 /* morph.c */; }; 676AC2F60668A939007173EB /* newdemo.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473D06687CF400DF26D8 /* newdemo.c */; }; 676AC2F70668A939007173EB /* newmenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4473F06687CF400DF26D8 /* newmenu.c */; }; 676AC2F80668A939007173EB /* object.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4474106687CF400DF26D8 /* object.c */; }; 676AC2F90668A939007173EB /* paging.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475906687CF400DF26D8 /* paging.c */; }; 676AC2FA0668A939007173EB /* physics.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475B06687CF400DF26D8 /* physics.c */; }; 676AC2FB0668A939007173EB /* piggy.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4475D06687CF400DF26D8 /* piggy.c */; }; 676AC2FD0668A939007173EB /* playsave.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476106687CF400DF26D8 /* playsave.c */; }; 676AC2FE0668A939007173EB /* polyobj.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476306687CF400DF26D8 /* polyobj.c */; }; 676AC2FF0668A939007173EB /* powerup.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476506687CF400DF26D8 /* powerup.c */; }; 676AC3000668A939007173EB /* render.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476706687CF400DF26D8 /* render.c */; }; 676AC3010668A939007173EB /* robot.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476A06687CF400DF26D8 /* robot.c */; }; 676AC3020668A939007173EB /* scores.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4476C06687CF400DF26D8 /* scores.c */; }; 676AC3040668A939007173EB /* slew.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477206687CF400DF26D8 /* slew.c */; }; 676AC3050668A939007173EB /* songs.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477406687CF400DF26D8 /* songs.c */; }; 676AC3060668A939007173EB /* state.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477706687CF400DF26D8 /* state.c */; }; 676AC3070668A939007173EB /* switch.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477906687CF400DF26D8 /* switch.c */; }; 676AC3080668A939007173EB /* terrain.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477B06687CF400DF26D8 /* terrain.c */; }; 676AC3090668A939007173EB /* texmerge.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477D06687CF400DF26D8 /* texmerge.c */; }; 676AC30A0668A939007173EB /* text.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4477F06687CF500DF26D8 /* text.c */; }; 676AC30B0668A939007173EB /* titles.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478206687CF500DF26D8 /* titles.c */; }; 676AC30C0668A939007173EB /* vclip.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478406687CF500DF26D8 /* vclip.c */; }; 676AC30D0668A939007173EB /* wall.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478706687CF500DF26D8 /* wall.c */; }; 676AC30E0668A939007173EB /* weapon.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4478906687CF500DF26D8 /* weapon.c */; }; 676AC30F0668A939007173EB /* fixc.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484B06687DCE00DF26D8 /* fixc.c */; }; 676AC3100668A939007173EB /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484D06687DCE00DF26D8 /* rand.c */; }; 676AC3110668A939007173EB /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484E06687DCE00DF26D8 /* tables.c */; }; 676AC3120668A939007173EB /* vecmat.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4484F06687DCE00DF26D8 /* vecmat.c */; }; 676AC3130668A939007173EB /* mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4485E06687DFB00DF26D8 /* mem.c */; }; 676AC3160668A939007173EB /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4486A06687E1000DF26D8 /* error.c */; }; 676AC3180668A939007173EB /* strio.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4487206687E1000DF26D8 /* strio.c */; }; 676AC3190668A939007173EB /* strutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4487306687E1000DF26D8 /* strutil.c */; }; 676AC31A0668A939007173EB /* ntmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4488806687E5E00DF26D8 /* ntmap.c */; }; 676AC31B0668A939007173EB /* scanline.c in Sources */ = {isa = PBXBuildFile; fileRef = 67B4488906687E5E00DF26D8 /* scanline.c */; }; 67F6FED2066B13B400443922 /* SDLMain.h in Headers */ = {isa = PBXBuildFile; fileRef = 67F6FED0066B13B400443922 /* SDLMain.h */; }; 67F6FED3066B13B400443922 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 67F6FED1066B13B400443922 /* SDLMain.m */; }; 67F6FED4066B13B400443922 /* SDLMain.h in Headers */ = {isa = PBXBuildFile; fileRef = 67F6FED0066B13B400443922 /* SDLMain.h */; }; 67F6FED5066B13B400443922 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 67F6FED1066B13B400443922 /* SDLMain.m */; }; EB0929F912A10889004D9A79 /* messagebox.h in Headers */ = {isa = PBXBuildFile; fileRef = EB0929F712A10889004D9A79 /* messagebox.h */; }; EB0929FA12A10889004D9A79 /* messagebox.c in Sources */ = {isa = PBXBuildFile; fileRef = EB0929F812A10889004D9A79 /* messagebox.c */; }; EB0929FB12A10889004D9A79 /* messagebox.h in Headers */ = {isa = PBXBuildFile; fileRef = EB0929F712A10889004D9A79 /* messagebox.h */; }; EB0929FC12A10889004D9A79 /* messagebox.c in Sources */ = {isa = PBXBuildFile; fileRef = EB0929F812A10889004D9A79 /* messagebox.c */; }; EB092A4A12A21A14004D9A79 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB092A4912A21A14004D9A79 /* Carbon.framework */; }; EB092A4B12A21A14004D9A79 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB092A4912A21A14004D9A79 /* Carbon.framework */; }; EB1405BA12100883002B1CC6 /* physfsx.c in Sources */ = {isa = PBXBuildFile; fileRef = EB1405B912100883002B1CC6 /* physfsx.c */; }; EB1405BB12100883002B1CC6 /* physfsx.c in Sources */ = {isa = PBXBuildFile; fileRef = EB1405B912100883002B1CC6 /* physfsx.c */; }; EB28D99C0ECEABD700E68E9B /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = EB28D99B0ECEABD700E68E9B /* init.c */; }; EB28D99D0ECEABD700E68E9B /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = EB28D99B0ECEABD700E68E9B /* init.c */; }; EB2C86E612C36FFB0073E30E /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651920890CEAE004FCAA3 /* file.c */; }; EB2EEB6910C5F8A3005256F2 /* net_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 17DFA6AF10C1A29500674D11 /* net_udp.c */; }; EB3319850D50A6B200C799B0 /* bmread.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC652010890D632004FCAA3 /* bmread.c */; }; EB33198F0D50A70600C799B0 /* snddecom.c in Sources */ = {isa = PBXBuildFile; fileRef = EBEEB2680D2B364300FF39B4 /* snddecom.c */; }; EB331A0C0D53578800C799B0 /* snddecom.c in Sources */ = {isa = PBXBuildFile; fileRef = EBEEB2680D2B364300FF39B4 /* snddecom.c */; }; EB35ABE10FB199B800C36930 /* window.h in Headers */ = {isa = PBXBuildFile; fileRef = EB35ABDF0FB199B800C36930 /* window.h */; }; EB35ABE20FB199B800C36930 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = EB35ABE00FB199B800C36930 /* window.c */; }; EB35ABE30FB199B800C36930 /* window.h in Headers */ = {isa = PBXBuildFile; fileRef = EB35ABDF0FB199B800C36930 /* window.h */; }; EB35ABE40FB199B800C36930 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = EB35ABE00FB199B800C36930 /* window.c */; }; EB380D7D0E168B1900EBD9AD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = EB380D7B0E168B1900EBD9AD /* InfoPlist.strings */; }; EB380D7E0E168B1900EBD9AD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = EB380D7B0E168B1900EBD9AD /* InfoPlist.strings */; }; EB6142611501EDC9004E2AE8 /* curve.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142451501EDC9004E2AE8 /* curve.pad */; }; EB6142621501EDC9004E2AE8 /* dummy.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142461501EDC9004E2AE8 /* dummy.pad */; }; EB6142631501EDC9004E2AE8 /* group.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142471501EDC9004E2AE8 /* group.pad */; }; EB6142641501EDC9004E2AE8 /* lighting.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142481501EDC9004E2AE8 /* lighting.pad */; }; EB6142651501EDC9004E2AE8 /* med.mnu in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142491501EDC9004E2AE8 /* med.mnu */; }; EB6142661501EDC9004E2AE8 /* newobj.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424A1501EDC9004E2AE8 /* newobj.pad */; }; EB6142671501EDC9004E2AE8 /* object.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424B1501EDC9004E2AE8 /* object.pad */; }; EB6142681501EDC9004E2AE8 /* objmov.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424C1501EDC9004E2AE8 /* objmov.pad */; }; EB6142691501EDC9004E2AE8 /* pc6x8.fnt in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424D1501EDC9004E2AE8 /* pc6x8.fnt */; }; EB61426A1501EDC9004E2AE8 /* pc8x16.fnt in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424E1501EDC9004E2AE8 /* pc8x16.fnt */; }; EB61426B1501EDC9004E2AE8 /* segmove.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424F1501EDC9004E2AE8 /* segmove.pad */; }; EB61426C1501EDC9004E2AE8 /* segsize.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142501501EDC9004E2AE8 /* segsize.pad */; }; EB61426D1501EDC9004E2AE8 /* test.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142511501EDC9004E2AE8 /* test.pad */; }; EB61426E1501EDC9004E2AE8 /* texture.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142521501EDC9004E2AE8 /* texture.pad */; }; EB61427E1501F2FB004E2AE8 /* d1xgl-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 67F6FEEA066B13D900443922 /* d1xgl-Info.plist */; }; EB775A7A105611720036C348 /* extractD1Data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EB775A79105611720036C348 /* extractD1Data.cpp */; }; EB8BE84F1071FBE00069486E /* player.c in Sources */ = {isa = PBXBuildFile; fileRef = EB8BE84E1071FBE00069486E /* player.c */; }; EB8BE8501071FBE00069486E /* player.c in Sources */ = {isa = PBXBuildFile; fileRef = EB8BE84E1071FBE00069486E /* player.c */; }; EB91A41012617070009E0095 /* libphysfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB91A40F12617070009E0095 /* libphysfs.dylib */; }; EB91A41112617070009E0095 /* libphysfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB91A40F12617070009E0095 /* libphysfs.dylib */; }; EB91A41312617084009E0095 /* libphysfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB91A41212617084009E0095 /* libphysfs.dylib */; }; EB91A41412617084009E0095 /* libphysfs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB91A41212617084009E0095 /* libphysfs.dylib */; }; EB92BE600CDD693C0045A32C /* digi_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5C0CDD693C0045A32C /* digi_audio.c */; }; EB92BE610CDD693C0045A32C /* digi_mixer_music.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5D0CDD693C0045A32C /* digi_mixer_music.c */; }; EB92BE620CDD693C0045A32C /* digi_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5E0CDD693C0045A32C /* digi_mixer.c */; }; EB92BE630CDD693C0045A32C /* jukebox.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5F0CDD693C0045A32C /* jukebox.c */; }; EB92BE640CDD693C0045A32C /* digi_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5C0CDD693C0045A32C /* digi_audio.c */; }; EB92BE650CDD693C0045A32C /* digi_mixer_music.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5D0CDD693C0045A32C /* digi_mixer_music.c */; }; EB92BE660CDD693C0045A32C /* digi_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5E0CDD693C0045A32C /* digi_mixer.c */; }; EB92BE670CDD693C0045A32C /* jukebox.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BE5F0CDD693C0045A32C /* jukebox.c */; }; EB92BEA60CDD6A570045A32C /* dl_list.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BEA40CDD6A570045A32C /* dl_list.c */; }; EB92BEA80CDD6A570045A32C /* dl_list.c in Sources */ = {isa = PBXBuildFile; fileRef = EB92BEA40CDD6A570045A32C /* dl_list.c */; }; EB92BEC60CDD6B4B0045A32C /* SDL_mixer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB92BEC40CDD6B4B0045A32C /* SDL_mixer.framework */; }; EB9E8DF30D66C2570099B0B5 /* d1x-rebirth.icns in Resources */ = {isa = PBXBuildFile; fileRef = EBAEB74B0BF4A86F00FC6E13 /* d1x-rebirth.icns */; }; EBAC98FB0D42497F0017D4BC /* ignorecase.c in Sources */ = {isa = PBXBuildFile; fileRef = EBAC98F90D42497F0017D4BC /* ignorecase.c */; }; EBAC98FD0D42497F0017D4BC /* ignorecase.c in Sources */ = {isa = PBXBuildFile; fileRef = EBAC98F90D42497F0017D4BC /* ignorecase.c */; }; EBAC9A171525C56300F6C779 /* inputbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651970890CEAE004FCAA3 /* inputbox.c */; }; EBAC9A181525C56D00F6C779 /* button.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651900890CEAE004FCAA3 /* button.c */; }; EBAC9A191525C56D00F6C779 /* checkbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651910890CEAE004FCAA3 /* checkbox.c */; }; EBAC9A1A1525C56D00F6C779 /* dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A90890CEAE004FCAA3 /* dialog.c */; }; EBAC9A1B1525C56D00F6C779 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651920890CEAE004FCAA3 /* file.c */; }; EBAC9A1C1525C56D00F6C779 /* gadget.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651940890CEAE004FCAA3 /* gadget.c */; }; EBAC9A1D1525C56D00F6C779 /* icon.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651960890CEAE004FCAA3 /* icon.c */; }; EBAC9A1E1525C56D00F6C779 /* keypad.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651980890CEAE004FCAA3 /* keypad.c */; }; EBAC9A1F1525C56D00F6C779 /* keypress.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651990890CEAE004FCAA3 /* keypress.c */; }; EBAC9A201525C56D00F6C779 /* keytrap.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519A0890CEAE004FCAA3 /* keytrap.c */; }; EBAC9A211525C56D00F6C779 /* listbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519B0890CEAE004FCAA3 /* listbox.c */; }; EBAC9A221525C56D00F6C779 /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519E0890CEAE004FCAA3 /* menu.c */; }; EBAC9A231525C56D00F6C779 /* menubar.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519F0890CEAE004FCAA3 /* menubar.c */; }; EBAC9A241525C56D00F6C779 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A00890CEAE004FCAA3 /* message.c */; }; EBAC9A251525C56D00F6C779 /* popup.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A30890CEAE004FCAA3 /* popup.c */; }; EBAC9A261525C56D00F6C779 /* radio.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A40890CEAE004FCAA3 /* radio.c */; }; EBAC9A271525C56D00F6C779 /* scroll.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A50890CEAE004FCAA3 /* scroll.c */; }; EBAC9A281525C56D00F6C779 /* ui.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A60890CEAE004FCAA3 /* ui.c */; }; EBAC9A291525C56D00F6C779 /* uidraw.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A70890CEAE004FCAA3 /* uidraw.c */; }; EBAC9A2A1525C56D00F6C779 /* userbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A80890CEAE004FCAA3 /* userbox.c */; }; EBAC9A2E1525C5CD00F6C779 /* curve.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142451501EDC9004E2AE8 /* curve.pad */; }; EBAC9A2F1525C5CD00F6C779 /* dummy.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142461501EDC9004E2AE8 /* dummy.pad */; }; EBAC9A301525C5CD00F6C779 /* group.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142471501EDC9004E2AE8 /* group.pad */; }; EBAC9A311525C5CD00F6C779 /* lighting.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142481501EDC9004E2AE8 /* lighting.pad */; }; EBAC9A321525C5CD00F6C779 /* med.mnu in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142491501EDC9004E2AE8 /* med.mnu */; }; EBAC9A331525C5CD00F6C779 /* newobj.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424A1501EDC9004E2AE8 /* newobj.pad */; }; EBAC9A341525C5CD00F6C779 /* object.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424B1501EDC9004E2AE8 /* object.pad */; }; EBAC9A351525C5CD00F6C779 /* objmov.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424C1501EDC9004E2AE8 /* objmov.pad */; }; EBAC9A361525C5CD00F6C779 /* pc6x8.fnt in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424D1501EDC9004E2AE8 /* pc6x8.fnt */; }; EBAC9A371525C5CD00F6C779 /* pc8x16.fnt in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424E1501EDC9004E2AE8 /* pc8x16.fnt */; }; EBAC9A381525C5CD00F6C779 /* segmove.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB61424F1501EDC9004E2AE8 /* segmove.pad */; }; EBAC9A391525C5CD00F6C779 /* segsize.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142501501EDC9004E2AE8 /* segsize.pad */; }; EBAC9A3A1525C5CD00F6C779 /* test.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142511501EDC9004E2AE8 /* test.pad */; }; EBAC9A3B1525C5CD00F6C779 /* texture.pad in CopyFiles */ = {isa = PBXBuildFile; fileRef = EB6142521501EDC9004E2AE8 /* texture.pad */; }; EBAC9A3C1525C5E800F6C779 /* autosave.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650800890C882004FCAA3 /* autosave.c */; }; EBAC9A3D1525C5E800F6C779 /* curve.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142451501EDC9004E2AE8 /* curve.pad */; }; EBAC9A3E1525C5E800F6C779 /* dummy.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142461501EDC9004E2AE8 /* dummy.pad */; }; EBAC9A3F1525C5E800F6C779 /* group.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142471501EDC9004E2AE8 /* group.pad */; }; EBAC9A401525C5E800F6C779 /* lighting.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142481501EDC9004E2AE8 /* lighting.pad */; }; EBAC9A411525C5E800F6C779 /* med.mnu in Resources */ = {isa = PBXBuildFile; fileRef = EB6142491501EDC9004E2AE8 /* med.mnu */; }; EBAC9A421525C5E800F6C779 /* newobj.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB61424A1501EDC9004E2AE8 /* newobj.pad */; }; EBAC9A431525C5E800F6C779 /* object.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB61424B1501EDC9004E2AE8 /* object.pad */; }; EBAC9A441525C5E800F6C779 /* objmov.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB61424C1501EDC9004E2AE8 /* objmov.pad */; }; EBAC9A451525C5E800F6C779 /* pc6x8.fnt in Resources */ = {isa = PBXBuildFile; fileRef = EB61424D1501EDC9004E2AE8 /* pc6x8.fnt */; }; EBAC9A461525C5E800F6C779 /* pc8x16.fnt in Resources */ = {isa = PBXBuildFile; fileRef = EB61424E1501EDC9004E2AE8 /* pc8x16.fnt */; }; EBAC9A471525C5E800F6C779 /* segmove.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB61424F1501EDC9004E2AE8 /* segmove.pad */; }; EBAC9A481525C5E800F6C779 /* segsize.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142501501EDC9004E2AE8 /* segsize.pad */; }; EBAC9A491525C5E800F6C779 /* test.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142511501EDC9004E2AE8 /* test.pad */; }; EBAC9A4A1525C5E800F6C779 /* texture.pad in Resources */ = {isa = PBXBuildFile; fileRef = EB6142521501EDC9004E2AE8 /* texture.pad */; }; EBAC9A4B1525C5E800F6C779 /* centers.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650970890C882004FCAA3 /* centers.c */; }; EBAC9A4C1525C5E800F6C779 /* curves.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650990890C882004FCAA3 /* curves.c */; }; EBAC9A4D1525C5E800F6C779 /* eglobal.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509B0890C882004FCAA3 /* eglobal.c */; }; EBAC9A4E1525C5E800F6C779 /* ehostage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509C0890C882004FCAA3 /* ehostage.c */; }; EBAC9A4F1525C5E800F6C779 /* elight.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509E0890C882004FCAA3 /* elight.c */; }; EBAC9A501525C5E800F6C779 /* eobject.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509F0890C882004FCAA3 /* eobject.c */; }; EBAC9A511525C5E800F6C779 /* eswitch.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A10890C882004FCAA3 /* eswitch.c */; }; EBAC9A521525C5E800F6C779 /* fixseg.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A30890C882004FCAA3 /* fixseg.c */; }; EBAC9A531525C5E800F6C779 /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A40890C882004FCAA3 /* func.c */; }; EBAC9A541525C5E800F6C779 /* group.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A50890C882004FCAA3 /* group.c */; }; EBAC9A551525C5E800F6C779 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A60890C882004FCAA3 /* info.c */; }; EBAC9A561525C5E800F6C779 /* kbuild.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A80890C882004FCAA3 /* kbuild.c */; }; EBAC9A571525C5E800F6C779 /* kcurve.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A90890C882004FCAA3 /* kcurve.c */; }; EBAC9A581525C5E800F6C779 /* kfuncs.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AB0890C882004FCAA3 /* kfuncs.c */; }; EBAC9A591525C5E800F6C779 /* kgame.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AD0890C882004FCAA3 /* kgame.c */; }; EBAC9A5B1525C5E800F6C779 /* khelp.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AF0890C882004FCAA3 /* khelp.c */; }; EBAC9A5C1525C5E800F6C779 /* kmine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B00890C882004FCAA3 /* kmine.c */; }; EBAC9A5D1525C5E800F6C779 /* ksegmove.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B10890C882004FCAA3 /* ksegmove.c */; }; EBAC9A5E1525C5E800F6C779 /* ksegsel.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B20890C882004FCAA3 /* ksegsel.c */; }; EBAC9A5F1525C5E800F6C779 /* ksegsize.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B30890C882004FCAA3 /* ksegsize.c */; }; EBAC9A601525C5E800F6C779 /* ktmap.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B40890C882004FCAA3 /* ktmap.c */; }; EBAC9A611525C5E800F6C779 /* kview.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B50890C882004FCAA3 /* kview.c */; }; EBAC9A631525C5E800F6C779 /* med.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B90890C882004FCAA3 /* med.c */; }; EBAC9A641525C5E800F6C779 /* meddraw.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BA0890C882004FCAA3 /* meddraw.c */; }; EBAC9A651525C5E800F6C779 /* medmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BD0890C882004FCAA3 /* medmisc.c */; }; EBAC9A661525C5E800F6C779 /* medrobot.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BF0890C882004FCAA3 /* medrobot.c */; }; EBAC9A671525C5E800F6C779 /* medsel.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C10890C882004FCAA3 /* medsel.c */; }; EBAC9A681525C5E800F6C779 /* medwall.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C30890C882004FCAA3 /* medwall.c */; }; EBAC9A691525C5E800F6C779 /* mine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C50890C882004FCAA3 /* mine.c */; }; EBAC9A6A1525C5E800F6C779 /* objpage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C60890C882004FCAA3 /* objpage.c */; }; EBAC9A6B1525C5E800F6C779 /* segment.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C80890C882004FCAA3 /* segment.c */; }; EBAC9A6C1525C5E800F6C779 /* seguvs.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C90890C882004FCAA3 /* seguvs.c */; }; EBAC9A6D1525C5E800F6C779 /* texpage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650CB0890C882004FCAA3 /* texpage.c */; }; EBAC9A6E1525C5E800F6C779 /* texture.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650CD0890C882004FCAA3 /* texture.c */; }; EBAC9A6F1525C64400F6C779 /* dumpmine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC652020890D632004FCAA3 /* dumpmine.c */; }; EBAEB74C0BF4A86F00FC6E13 /* d1x-rebirth.icns in Resources */ = {isa = PBXBuildFile; fileRef = EBAEB74B0BF4A86F00FC6E13 /* d1x-rebirth.icns */; }; EBAFC26E088E508D006329AD /* conf.h in Headers */ = {isa = PBXBuildFile; fileRef = EBAFC269088E508D006329AD /* conf.h */; }; EBAFC290088E67CD006329AD /* digiobj.c in Sources */ = {isa = PBXBuildFile; fileRef = EBAFC28F088E67CD006329AD /* digiobj.c */; }; EBAFC291088E67CD006329AD /* digiobj.c in Sources */ = {isa = PBXBuildFile; fileRef = EBAFC28F088E67CD006329AD /* digiobj.c */; }; EBAFC2C0088E6BC7006329AD /* conf.h in Headers */ = {isa = PBXBuildFile; fileRef = EBAFC269088E508D006329AD /* conf.h */; }; EBC4BAFA170E64540033D261 /* vers_id.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC4BAF9170E63E90033D261 /* vers_id.c */; }; EBC4BAFB170E64550033D261 /* vers_id.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC4BAF9170E63E90033D261 /* vers_id.c */; }; EBC4BB11170E660B0033D261 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC4BAFC170E64760033D261 /* hash.c */; }; EBC4BB12170E660C0033D261 /* hash.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC4BAFC170E64760033D261 /* hash.c */; }; EBC58E710D489E19007C8ABF /* args.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC58E700D489E19007C8ABF /* args.c */; }; EBC58E720D489E19007C8ABF /* args.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC58E700D489E19007C8ABF /* args.c */; }; EBC652030890D632004FCAA3 /* bmread.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC652010890D632004FCAA3 /* bmread.c */; }; EBC652040890D632004FCAA3 /* dumpmine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC652020890D632004FCAA3 /* dumpmine.c */; }; EBC652100890D6B7004FCAA3 /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC6520F0890D6B7004FCAA3 /* ui.h */; }; EBC652110890D6B7004FCAA3 /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC6520F0890D6B7004FCAA3 /* ui.h */; }; EBC652130890D6DF004FCAA3 /* func.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC652120890D6DF004FCAA3 /* func.h */; }; EBC652140890D6DF004FCAA3 /* func.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC652120890D6DF004FCAA3 /* func.h */; }; EBC858F4122E165800FA437D /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBC858F3122E165800FA437D /* ApplicationServices.framework */; }; EBC858F5122E165800FA437D /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EBC858F3122E165800FA437D /* ApplicationServices.framework */; }; EBCE794D0DE59565008D8F82 /* rbaudio.c in Sources */ = {isa = PBXBuildFile; fileRef = EBCE794C0DE59565008D8F82 /* rbaudio.c */; }; EBCE794E0DE59565008D8F82 /* rbaudio.c in Sources */ = {isa = PBXBuildFile; fileRef = EBCE794C0DE59565008D8F82 /* rbaudio.c */; }; EBE8D7D10FD385E1009D181F /* gamecntl.c in Sources */ = {isa = PBXBuildFile; fileRef = EBE8D7D00FD385E1009D181F /* gamecntl.c */; }; EBE8D7D20FD385E1009D181F /* gamecntl.c in Sources */ = {isa = PBXBuildFile; fileRef = EBE8D7D00FD385E1009D181F /* gamecntl.c */; }; EBE8D8900FDA76D1009D181F /* gamerend.c in Sources */ = {isa = PBXBuildFile; fileRef = EBE8D88F0FDA76D1009D181F /* gamerend.c */; }; EBE8D8910FDA76D1009D181F /* gamerend.c in Sources */ = {isa = PBXBuildFile; fileRef = EBE8D88F0FDA76D1009D181F /* gamerend.c */; }; EBECB64212C040EB00D660B3 /* autosave.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650800890C882004FCAA3 /* autosave.c */; }; EBECB64312C040EC00D660B3 /* centers.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650970890C882004FCAA3 /* centers.c */; }; EBECB64412C040ED00D660B3 /* curves.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650990890C882004FCAA3 /* curves.c */; }; EBECB64512C040EE00D660B3 /* eglobal.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509B0890C882004FCAA3 /* eglobal.c */; }; EBECB64612C040F400D660B3 /* ehostage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509C0890C882004FCAA3 /* ehostage.c */; }; EBECB64712C040F500D660B3 /* elight.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509E0890C882004FCAA3 /* elight.c */; }; EBECB64812C040F600D660B3 /* eobject.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6509F0890C882004FCAA3 /* eobject.c */; }; EBECB64912C040F800D660B3 /* eswitch.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A10890C882004FCAA3 /* eswitch.c */; }; EBECB64A12C040FC00D660B3 /* fixseg.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A30890C882004FCAA3 /* fixseg.c */; }; EBECB64B12C0410000D660B3 /* func.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A40890C882004FCAA3 /* func.c */; }; EBECB64C12C0410200D660B3 /* group.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A50890C882004FCAA3 /* group.c */; }; EBECB64D12C0410500D660B3 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A60890C882004FCAA3 /* info.c */; }; EBECB64E12C0410900D660B3 /* kbuild.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A80890C882004FCAA3 /* kbuild.c */; }; EBECB64F12C0410E00D660B3 /* kcurve.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650A90890C882004FCAA3 /* kcurve.c */; }; EBECB65012C0411000D660B3 /* kfuncs.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AB0890C882004FCAA3 /* kfuncs.c */; }; EBECB65112C0411400D660B3 /* kgame.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AD0890C882004FCAA3 /* kgame.c */; }; EBECB65212C0411900D660B3 /* khelp.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650AF0890C882004FCAA3 /* khelp.c */; }; EBECB65312C0411B00D660B3 /* kmine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B00890C882004FCAA3 /* kmine.c */; }; EBECB65412C0411F00D660B3 /* ksegmove.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B10890C882004FCAA3 /* ksegmove.c */; }; EBECB65512C0412000D660B3 /* ksegsel.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B20890C882004FCAA3 /* ksegsel.c */; }; EBECB65612C0412200D660B3 /* ksegsize.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B30890C882004FCAA3 /* ksegsize.c */; }; EBECB65712C0412400D660B3 /* ktmap.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B40890C882004FCAA3 /* ktmap.c */; }; EBECB65812C0412600D660B3 /* kview.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B50890C882004FCAA3 /* kview.c */; }; EBECB65A12C0413800D660B3 /* med.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650B90890C882004FCAA3 /* med.c */; }; EBECB65B12C0413C00D660B3 /* meddraw.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BA0890C882004FCAA3 /* meddraw.c */; }; EBECB65C12C0414100D660B3 /* medmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BD0890C882004FCAA3 /* medmisc.c */; }; EBECB65D12C0414D00D660B3 /* medrobot.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650BF0890C882004FCAA3 /* medrobot.c */; }; EBECB65E12C0415100D660B3 /* medsel.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C10890C882004FCAA3 /* medsel.c */; }; EBECB65F12C0415200D660B3 /* medwall.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C30890C882004FCAA3 /* medwall.c */; }; EBECB66012C0415400D660B3 /* mine.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C50890C882004FCAA3 /* mine.c */; }; EBECB66112C0415E00D660B3 /* objpage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C60890C882004FCAA3 /* objpage.c */; }; EBECB66212C0416000D660B3 /* segment.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C80890C882004FCAA3 /* segment.c */; }; EBECB66312C0416400D660B3 /* seguvs.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650C90890C882004FCAA3 /* seguvs.c */; }; EBECB66412C0416500D660B3 /* texpage.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650CB0890C882004FCAA3 /* texpage.c */; }; EBECB66512C0416600D660B3 /* texture.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC650CD0890C882004FCAA3 /* texture.c */; }; EBECB66612C0416F00D660B3 /* button.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651900890CEAE004FCAA3 /* button.c */; }; EBECB66712C0417300D660B3 /* checkbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651910890CEAE004FCAA3 /* checkbox.c */; }; EBECB66812C0417500D660B3 /* gadget.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651940890CEAE004FCAA3 /* gadget.c */; }; EBECB66912C0417700D660B3 /* icon.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651960890CEAE004FCAA3 /* icon.c */; }; EBECB66A12C0417D00D660B3 /* inputbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651970890CEAE004FCAA3 /* inputbox.c */; }; EBECB66B12C0418500D660B3 /* keypad.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651980890CEAE004FCAA3 /* keypad.c */; }; EBECB66C12C0418600D660B3 /* keypress.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651990890CEAE004FCAA3 /* keypress.c */; }; EBECB66D12C0418700D660B3 /* keytrap.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519A0890CEAE004FCAA3 /* keytrap.c */; }; EBECB66F12C0418F00D660B3 /* listbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519B0890CEAE004FCAA3 /* listbox.c */; }; EBECB67012C041C100D660B3 /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519E0890CEAE004FCAA3 /* menu.c */; }; EBECB67112C041C700D660B3 /* menubar.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC6519F0890CEAE004FCAA3 /* menubar.c */; }; EBECB67212C041CD00D660B3 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A00890CEAE004FCAA3 /* message.c */; }; EBECB67412C041D200D660B3 /* popup.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A30890CEAE004FCAA3 /* popup.c */; }; EBECB67512C041D500D660B3 /* radio.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A40890CEAE004FCAA3 /* radio.c */; }; EBECB67612C041DC00D660B3 /* scroll.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A50890CEAE004FCAA3 /* scroll.c */; }; EBECB67712C041E500D660B3 /* ui.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A60890CEAE004FCAA3 /* ui.c */; }; EBECB67812C041E800D660B3 /* uidraw.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A70890CEAE004FCAA3 /* uidraw.c */; }; EBECB67912C041EA00D660B3 /* userbox.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A80890CEAE004FCAA3 /* userbox.c */; }; EBECB67A12C041EB00D660B3 /* dialog.c in Sources */ = {isa = PBXBuildFile; fileRef = EBC651A90890CEAE004FCAA3 /* dialog.c */; }; EBEEB0AE0D2A2AEE00FF39B4 /* bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0AA0D2A2AEE00FF39B4 /* bitmap.h */; }; EBEEB0AF0D2A2AEE00FF39B4 /* clip.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0AB0D2A2AEE00FF39B4 /* clip.h */; }; EBEEB0B20D2A2AEF00FF39B4 /* bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0AA0D2A2AEE00FF39B4 /* bitmap.h */; }; EBEEB0B30D2A2AEF00FF39B4 /* clip.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0AB0D2A2AEE00FF39B4 /* clip.h */; }; EBEEB0B80D2A2B4500FF39B4 /* clipper.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0B60D2A2B4500FF39B4 /* clipper.h */; }; EBEEB0B90D2A2B4500FF39B4 /* globvars.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0B70D2A2B4500FF39B4 /* globvars.h */; }; EBEEB0BA0D2A2B4500FF39B4 /* clipper.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0B60D2A2B4500FF39B4 /* clipper.h */; }; EBEEB0BB0D2A2B4500FF39B4 /* globvars.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB0B70D2A2B4500FF39B4 /* globvars.h */; }; EBEEB1050D2A307300FF39B4 /* scanline.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1030D2A307300FF39B4 /* scanline.h */; }; EBEEB1060D2A307300FF39B4 /* texmapl.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1040D2A307300FF39B4 /* texmapl.h */; }; EBEEB1070D2A307300FF39B4 /* scanline.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1030D2A307300FF39B4 /* scanline.h */; }; EBEEB1080D2A307300FF39B4 /* texmapl.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1040D2A307300FF39B4 /* texmapl.h */; }; EBEEB1E90D2B317800FF39B4 /* custom.c in Sources */ = {isa = PBXBuildFile; fileRef = EBEEB1E40D2B317700FF39B4 /* custom.c */; }; EBEEB1EA0D2B317800FF39B4 /* custom.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1E50D2B317700FF39B4 /* custom.h */; }; EBEEB1EE0D2B317800FF39B4 /* custom.c in Sources */ = {isa = PBXBuildFile; fileRef = EBEEB1E40D2B317700FF39B4 /* custom.c */; }; EBEEB1EF0D2B317800FF39B4 /* custom.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1E50D2B317700FF39B4 /* custom.h */; }; EBEEB2000D2B320C00FF39B4 /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1F40D2B320B00FF39B4 /* hash.h */; }; EBEEB20C0D2B320C00FF39B4 /* hash.h in Headers */ = {isa = PBXBuildFile; fileRef = EBEEB1F40D2B320B00FF39B4 /* hash.h */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ EB6142761501EFAB004E2AE8 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = editor; dstSubfolderSpec = 7; files = ( EB61426A1501EDC9004E2AE8 /* pc8x16.fnt in CopyFiles */, EB6142691501EDC9004E2AE8 /* pc6x8.fnt in CopyFiles */, EB6142651501EDC9004E2AE8 /* med.mnu in CopyFiles */, EB6142631501EDC9004E2AE8 /* group.pad in CopyFiles */, EB6142621501EDC9004E2AE8 /* dummy.pad in CopyFiles */, EB61426D1501EDC9004E2AE8 /* test.pad in CopyFiles */, EB61426B1501EDC9004E2AE8 /* segmove.pad in CopyFiles */, EB61426E1501EDC9004E2AE8 /* texture.pad in CopyFiles */, EB61426C1501EDC9004E2AE8 /* segsize.pad in CopyFiles */, EB6142661501EDC9004E2AE8 /* newobj.pad in CopyFiles */, EB6142611501EDC9004E2AE8 /* curve.pad in CopyFiles */, EB6142671501EDC9004E2AE8 /* object.pad in CopyFiles */, EB6142681501EDC9004E2AE8 /* objmov.pad in CopyFiles */, EB6142641501EDC9004E2AE8 /* lighting.pad in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; EBAC9A701525C67500F6C779 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = editor; dstSubfolderSpec = 7; files = ( EBAC9A2E1525C5CD00F6C779 /* curve.pad in CopyFiles */, EBAC9A2F1525C5CD00F6C779 /* dummy.pad in CopyFiles */, EBAC9A301525C5CD00F6C779 /* group.pad in CopyFiles */, EBAC9A311525C5CD00F6C779 /* lighting.pad in CopyFiles */, EBAC9A321525C5CD00F6C779 /* med.mnu in CopyFiles */, EBAC9A331525C5CD00F6C779 /* newobj.pad in CopyFiles */, EBAC9A341525C5CD00F6C779 /* object.pad in CopyFiles */, EBAC9A351525C5CD00F6C779 /* objmov.pad in CopyFiles */, EBAC9A361525C5CD00F6C779 /* pc6x8.fnt in CopyFiles */, EBAC9A371525C5CD00F6C779 /* pc8x16.fnt in CopyFiles */, EBAC9A381525C5CD00F6C779 /* segmove.pad in CopyFiles */, EBAC9A391525C5CD00F6C779 /* segsize.pad in CopyFiles */, EBAC9A3A1525C5CD00F6C779 /* test.pad in CopyFiles */, EBAC9A3B1525C5CD00F6C779 /* texture.pad in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 179E6E9A11F37B2400175C54 /* hmp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmp.h; sourceTree = ""; }; 179E6E9D11F37B3400175C54 /* hmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hmp.c; sourceTree = ""; }; 17DFA6AF10C1A29500674D11 /* net_udp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = net_udp.c; sourceTree = ""; }; 17DFA6B210C1A2A300674D11 /* net_udp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = net_udp.h; sourceTree = ""; }; 670E3796066C50C30085B671 /* CHANGELOG.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = CHANGELOG.txt; sourceTree = ""; }; 6710AAFE066B2D6100DB0F68 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = ""; }; 6710AB68066B2E0400DB0F68 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 675ED123066B196700E42AA7 /* d1x-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "d1x-Info.plist"; sourceTree = ""; }; 676032DC066B399A008A67A3 /* multi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = multi.c; sourceTree = ""; }; 676032DD066B399A008A67A3 /* multibot.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = multibot.c; sourceTree = ""; }; 676032F9066B39CE008A67A3 /* kmatrix.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kmatrix.c; sourceTree = ""; }; 676AC04E0668A814007173EB /* gr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gr.c; sourceTree = ""; }; 676AC0510668A814007173EB /* ogl.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ogl.c; sourceTree = ""; }; 676AC31D0668A939007173EB /* d1xgl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = d1xgl.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6791CE4F0668852C00056A5A /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = byteswap.h; sourceTree = ""; }; 6791CE500668852C00056A5A /* rle.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rle.h; sourceTree = ""; }; 6791CF420668881F00056A5A /* fix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fix.h; sourceTree = ""; }; 6791CF4E0668883900056A5A /* palette.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = palette.h; sourceTree = ""; }; 6791CF620668885500056A5A /* pcx.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pcx.h; sourceTree = ""; }; 6791CF8D066888DD00056A5A /* 3d.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = 3d.h; sourceTree = ""; }; 6791CFB10668891200056A5A /* texmap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = texmap.h; sourceTree = ""; }; 6791D00B066889CD00056A5A /* args.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = args.h; sourceTree = ""; }; 6791D026066889F100056A5A /* vecmat.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vecmat.h; sourceTree = ""; }; 6791D04B06688A2E00056A5A /* timer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = ""; }; 6791D08F06688A9C00056A5A /* maths.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = maths.h; sourceTree = ""; }; 6791D0A306688AB900056A5A /* strutil.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = strutil.h; sourceTree = ""; }; 6791D0BD06688AE800056A5A /* iff.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = iff.h; sourceTree = ""; }; 6791D1550668903B00056A5A /* strio.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = strio.h; sourceTree = ""; }; 67B44139066878B300DF26D8 /* 2dsline.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = 2dsline.c; sourceTree = ""; }; 67B4413A066878B300DF26D8 /* bitblt.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = bitblt.c; sourceTree = ""; }; 67B4413B066878B300DF26D8 /* bitmap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = bitmap.c; sourceTree = ""; }; 67B4413D066878B300DF26D8 /* box.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = box.c; sourceTree = ""; }; 67B4413E066878B300DF26D8 /* canvas.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = canvas.c; sourceTree = ""; }; 67B4413F066878B300DF26D8 /* circle.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = circle.c; sourceTree = ""; }; 67B44141066878B300DF26D8 /* disc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = disc.c; sourceTree = ""; }; 67B44142066878B300DF26D8 /* font.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = font.c; sourceTree = ""; }; 67B44143066878B300DF26D8 /* gpixel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gpixel.c; sourceTree = ""; }; 67B44145066878B300DF26D8 /* line.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = line.c; sourceTree = ""; }; 67B44148066878B300DF26D8 /* palette.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = palette.c; sourceTree = ""; }; 67B44149066878B300DF26D8 /* pcx.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = pcx.c; sourceTree = ""; }; 67B4414A066878B300DF26D8 /* pixel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = pixel.c; sourceTree = ""; }; 67B4414B066878B300DF26D8 /* poly.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = poly.c; sourceTree = ""; }; 67B4414C066878B300DF26D8 /* rect.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rect.c; sourceTree = ""; }; 67B4414D066878B300DF26D8 /* rle.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rle.c; sourceTree = ""; }; 67B44151066878B300DF26D8 /* scalec.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = scalec.c; sourceTree = ""; }; 67B441760668792300DF26D8 /* clipper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = clipper.c; sourceTree = ""; }; 67B441780668792300DF26D8 /* draw.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = draw.c; sourceTree = ""; }; 67B441790668792300DF26D8 /* globvars.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = globvars.c; sourceTree = ""; }; 67B4417B0668792300DF26D8 /* instance.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = instance.c; sourceTree = ""; }; 67B4417D0668792300DF26D8 /* interp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = interp.c; sourceTree = ""; }; 67B4417F0668792300DF26D8 /* matrix.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = matrix.c; sourceTree = ""; }; 67B441800668792300DF26D8 /* points.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = points.c; sourceTree = ""; }; 67B441810668792300DF26D8 /* rod.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rod.c; sourceTree = ""; }; 67B441820668792300DF26D8 /* setup.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = setup.c; sourceTree = ""; }; 67B441D306687A0200DF26D8 /* digi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digi.c; sourceTree = ""; }; 67B441D406687A0200DF26D8 /* event.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = event.c; sourceTree = ""; }; 67B441D506687A0200DF26D8 /* gr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gr.c; sourceTree = ""; }; 67B441D706687A0200DF26D8 /* joy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = joy.c; sourceTree = ""; }; 67B441D906687A0200DF26D8 /* key.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = key.c; sourceTree = ""; }; 67B441DB06687A0200DF26D8 /* mouse.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = mouse.c; sourceTree = ""; }; 67B441DD06687A0200DF26D8 /* timer.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = ""; }; 67B4420006687A9E00DF26D8 /* iff.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = iff.c; sourceTree = ""; }; 67B446CF06687CF400DF26D8 /* ai.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ai.c; sourceTree = ""; }; 67B446D206687CF400DF26D8 /* aipath.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = aipath.c; sourceTree = ""; }; 67B446D406687CF400DF26D8 /* automap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = automap.c; sourceTree = ""; }; 67B446D606687CF400DF26D8 /* bm.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = bm.c; sourceTree = ""; }; 67B446DB06687CF400DF26D8 /* cntrlcen.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cntrlcen.c; sourceTree = ""; }; 67B446DD06687CF400DF26D8 /* collide.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = collide.c; sourceTree = ""; }; 67B446E006687CF400DF26D8 /* config.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = config.c; sourceTree = ""; }; 67B446E206687CF400DF26D8 /* console.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = console.c; sourceTree = ""; }; 67B446E306687CF400DF26D8 /* controls.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = controls.c; sourceTree = ""; }; 67B446E506687CF400DF26D8 /* credits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = credits.c; sourceTree = ""; }; 67B446F706687CF400DF26D8 /* effects.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = effects.c; sourceTree = ""; }; 67B446F906687CF400DF26D8 /* endlevel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = endlevel.c; sourceTree = ""; }; 67B446FD06687CF400DF26D8 /* fireball.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fireball.c; sourceTree = ""; }; 67B446FF06687CF400DF26D8 /* fuelcen.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fuelcen.c; sourceTree = ""; }; 67B4470106687CF400DF26D8 /* fvi.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fvi.c; sourceTree = ""; }; 67B4470406687CF400DF26D8 /* game.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = game.c; sourceTree = ""; }; 67B4470706687CF400DF26D8 /* gamefont.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gamefont.c; sourceTree = ""; }; 67B4470906687CF400DF26D8 /* gamemine.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gamemine.c; sourceTree = ""; }; 67B4470E06687CF400DF26D8 /* gamesave.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gamesave.c; sourceTree = ""; }; 67B4471006687CF400DF26D8 /* gameseg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gameseg.c; sourceTree = ""; }; 67B4471206687CF400DF26D8 /* gameseq.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gameseq.c; sourceTree = ""; }; 67B4471506687CF400DF26D8 /* gauges.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gauges.c; sourceTree = ""; }; 67B4471706687CF400DF26D8 /* hostage.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = hostage.c; sourceTree = ""; }; 67B4471906687CF400DF26D8 /* hud.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = hud.c; sourceTree = ""; }; 67B4471B06687CF400DF26D8 /* inferno.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = inferno.c; sourceTree = ""; }; 67B4472006687CF400DF26D8 /* kconfig.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kconfig.c; sourceTree = ""; }; 67B4472506687CF400DF26D8 /* laser.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = laser.c; sourceTree = ""; }; 67B4472706687CF400DF26D8 /* lighting.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = lighting.c; sourceTree = ""; }; 67B4472B06687CF400DF26D8 /* menu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = menu.c; sourceTree = ""; }; 67B4472D06687CF400DF26D8 /* mglobal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = mglobal.c; sourceTree = ""; }; 67B4472E06687CF400DF26D8 /* mission.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = mission.c; sourceTree = ""; }; 67B4473106687CF400DF26D8 /* morph.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = morph.c; sourceTree = ""; }; 67B4473D06687CF400DF26D8 /* newdemo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = newdemo.c; sourceTree = ""; }; 67B4473F06687CF400DF26D8 /* newmenu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = newmenu.c; sourceTree = ""; }; 67B4474106687CF400DF26D8 /* object.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = object.c; sourceTree = ""; }; 67B4475906687CF400DF26D8 /* paging.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = paging.c; sourceTree = ""; }; 67B4475B06687CF400DF26D8 /* physics.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = physics.c; sourceTree = ""; }; 67B4475D06687CF400DF26D8 /* piggy.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = piggy.c; sourceTree = ""; }; 67B4476106687CF400DF26D8 /* playsave.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = playsave.c; sourceTree = ""; }; 67B4476306687CF400DF26D8 /* polyobj.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = polyobj.c; sourceTree = ""; }; 67B4476506687CF400DF26D8 /* powerup.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = powerup.c; sourceTree = ""; }; 67B4476706687CF400DF26D8 /* render.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = render.c; sourceTree = ""; }; 67B4476A06687CF400DF26D8 /* robot.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = robot.c; sourceTree = ""; }; 67B4476C06687CF400DF26D8 /* scores.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = scores.c; sourceTree = ""; }; 67B4477206687CF400DF26D8 /* slew.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = slew.c; sourceTree = ""; }; 67B4477406687CF400DF26D8 /* songs.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = songs.c; sourceTree = ""; }; 67B4477706687CF400DF26D8 /* state.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = state.c; sourceTree = ""; }; 67B4477906687CF400DF26D8 /* switch.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = switch.c; sourceTree = ""; }; 67B4477B06687CF400DF26D8 /* terrain.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = terrain.c; sourceTree = ""; }; 67B4477D06687CF400DF26D8 /* texmerge.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = texmerge.c; sourceTree = ""; }; 67B4477F06687CF500DF26D8 /* text.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = text.c; sourceTree = ""; }; 67B4478206687CF500DF26D8 /* titles.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = titles.c; sourceTree = ""; }; 67B4478406687CF500DF26D8 /* vclip.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vclip.c; sourceTree = ""; }; 67B4478706687CF500DF26D8 /* wall.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = wall.c; sourceTree = ""; }; 67B4478906687CF500DF26D8 /* weapon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = weapon.c; sourceTree = ""; }; 67B4484B06687DCE00DF26D8 /* fixc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fixc.c; sourceTree = ""; }; 67B4484D06687DCE00DF26D8 /* rand.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rand.c; sourceTree = ""; }; 67B4484E06687DCE00DF26D8 /* tables.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = tables.c; sourceTree = ""; }; 67B4484F06687DCE00DF26D8 /* vecmat.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = vecmat.c; sourceTree = ""; }; 67B4485E06687DFB00DF26D8 /* mem.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = mem.c; sourceTree = ""; }; 67B4486A06687E1000DF26D8 /* error.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = ""; }; 67B4487206687E1000DF26D8 /* strio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = strio.c; sourceTree = ""; }; 67B4487306687E1000DF26D8 /* strutil.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = strutil.c; sourceTree = ""; }; 67B4488806687E5E00DF26D8 /* ntmap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ntmap.c; sourceTree = ""; }; 67B4488906687E5E00DF26D8 /* scanline.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = scanline.c; sourceTree = ""; }; 67B4489206687E5E00DF26D8 /* tmapflat.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = tmapflat.c; sourceTree = ""; }; 67B4490F066880A300DF26D8 /* u_mem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = u_mem.h; sourceTree = ""; }; 67B44914066880C400DF26D8 /* gr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gr.h; sourceTree = ""; }; 67B44915066880C400DF26D8 /* grdef.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = grdef.h; sourceTree = ""; }; 67F6FED0066B13B400443922 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDLMain.h; path = arch/cocoa/SDLMain.h; sourceTree = ""; }; 67F6FED1066B13B400443922 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = SDLMain.m; path = arch/cocoa/SDLMain.m; sourceTree = ""; }; 67F6FEEA066B13D900443922 /* d1xgl-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "d1xgl-Info.plist"; sourceTree = ""; }; EB01AFA90A65323200EA4C7C /* newdemo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = newdemo.h; sourceTree = ""; }; EB0420B90A341041002CC961 /* multi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = multi.h; sourceTree = ""; }; EB0420BB0A341042002CC961 /* morph.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = morph.h; sourceTree = ""; }; EB0420BD0A341042002CC961 /* mission.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mission.h; sourceTree = ""; }; EB0420BE0A341042002CC961 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = ""; }; EB0420BF0A341042002CC961 /* cntrlcen.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cntrlcen.h; sourceTree = ""; }; EB0420C10A341042002CC961 /* weapon.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = weapon.h; sourceTree = ""; }; EB0420C20A341042002CC961 /* wall.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = wall.h; sourceTree = ""; }; EB0420C30A341042002CC961 /* vers_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vers_id.h; sourceTree = ""; }; EB0420C40A341042002CC961 /* vclip.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = vclip.h; sourceTree = ""; }; EB0420C50A341042002CC961 /* titles.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = titles.h; sourceTree = ""; }; EB0420C60A341042002CC961 /* textures.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = textures.h; sourceTree = ""; }; EB0420C70A341042002CC961 /* text.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = text.h; sourceTree = ""; }; EB0420C80A341042002CC961 /* texmerge.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = texmerge.h; sourceTree = ""; }; EB0420C90A341042002CC961 /* terrain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = terrain.h; sourceTree = ""; }; EB0420CA0A341042002CC961 /* switch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = switch.h; sourceTree = ""; }; EB0420CB0A341042002CC961 /* state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = state.h; sourceTree = ""; }; EB0420CC0A341042002CC961 /* sounds.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sounds.h; sourceTree = ""; }; EB0420CD0A341042002CC961 /* songs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = songs.h; sourceTree = ""; }; EB0420CE0A341042002CC961 /* slew.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = slew.h; sourceTree = ""; }; EB0420CF0A341042002CC961 /* segpoint.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = segpoint.h; sourceTree = ""; }; EB0420D00A341042002CC961 /* segment.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = segment.h; sourceTree = ""; }; EB0420D10A341042002CC961 /* screens.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = screens.h; sourceTree = ""; }; EB0420D20A341042002CC961 /* scores.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = scores.h; sourceTree = ""; }; EB0420D30A341042002CC961 /* robot.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = robot.h; sourceTree = ""; }; EB0420D50A341042002CC961 /* render.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = render.h; sourceTree = ""; }; EB0420D60A341042002CC961 /* powerup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = powerup.h; sourceTree = ""; }; EB0420D70A341042002CC961 /* polyobj.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = polyobj.h; sourceTree = ""; }; EB0420D80A341042002CC961 /* playsave.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = playsave.h; sourceTree = ""; }; EB0420D90A341042002CC961 /* player.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = player.h; sourceTree = ""; }; EB0420DA0A341042002CC961 /* piggy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = piggy.h; sourceTree = ""; }; EB0420DB0A341042002CC961 /* physics.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = physics.h; sourceTree = ""; }; EB0420DC0A341042002CC961 /* paging.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = paging.h; sourceTree = ""; }; EB0420DD0A341042002CC961 /* object.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = object.h; sourceTree = ""; }; EB0420DE0A341042002CC961 /* newmenu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = newmenu.h; sourceTree = ""; }; EB0420E10A341042002CC961 /* digi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = digi.h; sourceTree = ""; }; EB0420E30A341042002CC961 /* gameseq.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gameseq.h; sourceTree = ""; }; EB0420E50A341042002CC961 /* credits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = credits.h; sourceTree = ""; }; EB0420E70A341042002CC961 /* multibot.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = multibot.h; sourceTree = ""; }; EB0420E80A341042002CC961 /* gameseg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gameseg.h; sourceTree = ""; }; EB0420E90A341042002CC961 /* gamesave.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamesave.h; sourceTree = ""; }; EB0420EB0A341042002CC961 /* gamemine.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamemine.h; sourceTree = ""; }; EB0420EC0A341042002CC961 /* gamefont.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gamefont.h; sourceTree = ""; }; EB0420ED0A341042002CC961 /* game.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = game.h; sourceTree = ""; }; EB0420EF0A341042002CC961 /* fvi.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fvi.h; sourceTree = ""; }; EB0420F00A341042002CC961 /* fuelcen.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fuelcen.h; sourceTree = ""; }; EB0420F10A341042002CC961 /* collide.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = collide.h; sourceTree = ""; }; EB0420F20A341042002CC961 /* kmatrix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kmatrix.h; sourceTree = ""; }; EB0420F30A341042002CC961 /* kconfig.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kconfig.h; sourceTree = ""; }; EB0420F50A341042002CC961 /* inferno.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = inferno.h; sourceTree = ""; }; EB0420F60A341042002CC961 /* hudmsg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = hudmsg.h; sourceTree = ""; }; EB0420F70A341042002CC961 /* hostage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = hostage.h; sourceTree = ""; }; EB0420F80A341042002CC961 /* gauges.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = gauges.h; sourceTree = ""; }; EB0420FA0A341042002CC961 /* lighting.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = lighting.h; sourceTree = ""; }; EB0420FC0A341042002CC961 /* laser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = laser.h; sourceTree = ""; }; EB0420FD0A341042002CC961 /* fireball.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = fireball.h; sourceTree = ""; }; EB0420FF0A341042002CC961 /* endlevel.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = endlevel.h; sourceTree = ""; }; EB0421000A341042002CC961 /* effects.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = effects.h; sourceTree = ""; }; EB0421010A341042002CC961 /* aistruct.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = aistruct.h; sourceTree = ""; }; EB0421020A341042002CC961 /* bm.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = bm.h; sourceTree = ""; }; EB0421030A341042002CC961 /* automap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = automap.h; sourceTree = ""; }; EB0421040A341042002CC961 /* ai.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ai.h; sourceTree = ""; }; EB0421050A341042002CC961 /* controls.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = controls.h; sourceTree = ""; }; EB0421060A341042002CC961 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; EB0929F712A10889004D9A79 /* messagebox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = messagebox.h; sourceTree = ""; }; EB0929F812A10889004D9A79 /* messagebox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = messagebox.c; sourceTree = ""; }; EB092A3A12A21527004D9A79 /* messagebox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = messagebox.c; sourceTree = ""; }; EB092A4912A21A14004D9A79 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; EB1283BE0D59D94800A991A3 /* d1x.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = d1x.app; sourceTree = BUILT_PRODUCTS_DIR; }; EB1405B912100883002B1CC6 /* physfsx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = physfsx.c; sourceTree = ""; }; EB28D99B0ECEABD700E68E9B /* init.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = ""; }; EB3319E70D53341900C799B0 /* digi_audio.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = digi_audio.h; sourceTree = ""; }; EB3319E80D53341900C799B0 /* digi_mixer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = digi_mixer.h; sourceTree = ""; }; EB3319E90D53341900C799B0 /* digi_mixer_music.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = digi_mixer_music.h; sourceTree = ""; }; EB3319EA0D53341900C799B0 /* event.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = event.h; sourceTree = ""; }; EB3319EB0D53341900C799B0 /* joy.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = joy.h; sourceTree = ""; }; EB3319ED0D53341900C799B0 /* jukebox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = jukebox.h; sourceTree = ""; }; EB3319EE0D53341900C799B0 /* key.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = key.h; sourceTree = ""; }; EB3319EF0D53341900C799B0 /* mouse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = mouse.h; sourceTree = ""; }; EB3319F00D5334B600C799B0 /* internal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = ""; }; EB3319F10D53351600C799B0 /* loadgl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = loadgl.h; sourceTree = ""; }; EB3319F20D53351600C799B0 /* ogl_init.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ogl_init.h; sourceTree = ""; }; EB35ABDF0FB199B800C36930 /* window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = ""; }; EB35ABE00FB199B800C36930 /* window.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = window.c; sourceTree = ""; }; EB380D7C0E168B1900EBD9AD /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; EB6142451501EDC9004E2AE8 /* curve.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = curve.pad; sourceTree = ""; }; EB6142461501EDC9004E2AE8 /* dummy.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dummy.pad; sourceTree = ""; }; EB6142471501EDC9004E2AE8 /* group.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = group.pad; sourceTree = ""; }; EB6142481501EDC9004E2AE8 /* lighting.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = lighting.pad; sourceTree = ""; }; EB6142491501EDC9004E2AE8 /* med.mnu */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = med.mnu; sourceTree = ""; }; EB61424A1501EDC9004E2AE8 /* newobj.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = newobj.pad; sourceTree = ""; }; EB61424B1501EDC9004E2AE8 /* object.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = object.pad; sourceTree = ""; }; EB61424C1501EDC9004E2AE8 /* objmov.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = objmov.pad; sourceTree = ""; }; EB61424D1501EDC9004E2AE8 /* pc6x8.fnt */ = {isa = PBXFileReference; lastKnownFileType = file; path = pc6x8.fnt; sourceTree = ""; }; EB61424E1501EDC9004E2AE8 /* pc8x16.fnt */ = {isa = PBXFileReference; lastKnownFileType = file; path = pc8x16.fnt; sourceTree = ""; }; EB61424F1501EDC9004E2AE8 /* segmove.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = segmove.pad; sourceTree = ""; }; EB6142501501EDC9004E2AE8 /* segsize.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = segsize.pad; sourceTree = ""; }; EB6142511501EDC9004E2AE8 /* test.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = test.pad; sourceTree = ""; }; EB6142521501EDC9004E2AE8 /* texture.pad */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = texture.pad; sourceTree = ""; }; EB775A6F105611320036C348 /* d1Extract */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = d1Extract; sourceTree = BUILT_PRODUCTS_DIR; }; EB775A79105611720036C348 /* extractD1Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extractD1Data.cpp; sourceTree = ""; }; EB8BE84E1071FBE00069486E /* player.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = player.c; sourceTree = ""; }; EB9181090DABA47B0010CB39 /* console.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = ""; }; EB91A40F12617070009E0095 /* libphysfs.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libphysfs.dylib; path = ../physfs/build/Debug/libphysfs.dylib; sourceTree = SOURCE_ROOT; }; EB91A41212617084009E0095 /* libphysfs.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libphysfs.dylib; path = ../physfs/build/Release/libphysfs.dylib; sourceTree = SOURCE_ROOT; }; EB92BE5C0CDD693C0045A32C /* digi_audio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digi_audio.c; sourceTree = ""; }; EB92BE5D0CDD693C0045A32C /* digi_mixer_music.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digi_mixer_music.c; sourceTree = ""; }; EB92BE5E0CDD693C0045A32C /* digi_mixer.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digi_mixer.c; sourceTree = ""; }; EB92BE5F0CDD693C0045A32C /* jukebox.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = jukebox.c; sourceTree = ""; }; EB92BE680CDD69830045A32C /* dl_list.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dl_list.h; sourceTree = ""; }; EB92BEA40CDD6A570045A32C /* dl_list.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = dl_list.c; sourceTree = ""; }; EB92BEC40CDD6B4B0045A32C /* SDL_mixer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_mixer.framework; path = /Library/Frameworks/SDL_mixer.framework; sourceTree = ""; }; EBAC98F90D42497F0017D4BC /* ignorecase.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ignorecase.c; sourceTree = ""; }; EBAC994E0D4250320017D4BC /* ignorecase.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ignorecase.h; sourceTree = ""; }; EBAC99500D4250320017D4BC /* physfsx.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = physfsx.h; sourceTree = ""; }; EBAEB74B0BF4A86F00FC6E13 /* d1x-rebirth.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = "d1x-rebirth.icns"; path = "arch/cocoa/d1x-rebirth.icns"; sourceTree = ""; }; EBAFC269088E508D006329AD /* conf.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = conf.h; sourceTree = ""; }; EBAFC26A088E508D006329AD /* descent.r */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.rez; path = descent.r; sourceTree = ""; }; EBAFC26D088E508D006329AD /* SDL_main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SDL_main.c; sourceTree = ""; }; EBAFC28F088E67CD006329AD /* digiobj.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digiobj.c; sourceTree = ""; }; EBC4BAF4170E62160033D261 /* dxxerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dxxerror.h; sourceTree = ""; }; EBC4BAF5170E62160033D261 /* makesig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = makesig.h; sourceTree = ""; }; EBC4BAF6170E62C60033D261 /* tool_bundle.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = tool_bundle.py; path = arch/cocoa/tool_bundle.py; sourceTree = ""; }; EBC4BAF7170E63380033D261 /* d1x-rebirth.rc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "d1x-rebirth.rc"; sourceTree = ""; }; EBC4BAF8170E63890033D261 /* esegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = esegment.h; sourceTree = ""; }; EBC4BAF9170E63E90033D261 /* vers_id.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vers_id.c; sourceTree = ""; }; EBC4BAFC170E64760033D261 /* hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hash.c; sourceTree = ""; }; EBC58E700D489E19007C8ABF /* args.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = args.c; sourceTree = ""; }; EBC650800890C882004FCAA3 /* autosave.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = autosave.c; sourceTree = ""; }; EBC650970890C882004FCAA3 /* centers.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = centers.c; sourceTree = ""; }; EBC650990890C882004FCAA3 /* curves.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = curves.c; sourceTree = ""; }; EBC6509B0890C882004FCAA3 /* eglobal.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = eglobal.c; sourceTree = ""; }; EBC6509C0890C882004FCAA3 /* ehostage.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ehostage.c; sourceTree = ""; }; EBC6509E0890C882004FCAA3 /* elight.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = elight.c; sourceTree = ""; }; EBC6509F0890C882004FCAA3 /* eobject.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = eobject.c; sourceTree = ""; }; EBC650A10890C882004FCAA3 /* eswitch.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = eswitch.c; sourceTree = ""; }; EBC650A30890C882004FCAA3 /* fixseg.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fixseg.c; sourceTree = ""; }; EBC650A40890C882004FCAA3 /* func.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = func.c; sourceTree = ""; }; EBC650A50890C882004FCAA3 /* group.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = group.c; sourceTree = ""; }; EBC650A60890C882004FCAA3 /* info.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = info.c; sourceTree = ""; }; EBC650A80890C882004FCAA3 /* kbuild.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kbuild.c; sourceTree = ""; }; EBC650A90890C882004FCAA3 /* kcurve.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kcurve.c; sourceTree = ""; }; EBC650AB0890C882004FCAA3 /* kfuncs.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kfuncs.c; sourceTree = ""; }; EBC650AD0890C882004FCAA3 /* kgame.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kgame.c; sourceTree = ""; }; EBC650AF0890C882004FCAA3 /* khelp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = khelp.c; sourceTree = ""; }; EBC650B00890C882004FCAA3 /* kmine.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kmine.c; sourceTree = ""; }; EBC650B10890C882004FCAA3 /* ksegmove.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ksegmove.c; sourceTree = ""; }; EBC650B20890C882004FCAA3 /* ksegsel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ksegsel.c; sourceTree = ""; }; EBC650B30890C882004FCAA3 /* ksegsize.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ksegsize.c; sourceTree = ""; }; EBC650B40890C882004FCAA3 /* ktmap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ktmap.c; sourceTree = ""; }; EBC650B50890C882004FCAA3 /* kview.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = kview.c; sourceTree = ""; }; EBC650B90890C882004FCAA3 /* med.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = med.c; sourceTree = ""; }; EBC650BA0890C882004FCAA3 /* meddraw.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = meddraw.c; sourceTree = ""; }; EBC650BD0890C882004FCAA3 /* medmisc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = medmisc.c; sourceTree = ""; }; EBC650BF0890C882004FCAA3 /* medrobot.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = medrobot.c; sourceTree = ""; }; EBC650C10890C882004FCAA3 /* medsel.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = medsel.c; sourceTree = ""; }; EBC650C30890C882004FCAA3 /* medwall.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = medwall.c; sourceTree = ""; }; EBC650C50890C882004FCAA3 /* mine.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = mine.c; sourceTree = ""; }; EBC650C60890C882004FCAA3 /* objpage.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = objpage.c; sourceTree = ""; }; EBC650C80890C882004FCAA3 /* segment.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = segment.c; sourceTree = ""; }; EBC650C90890C882004FCAA3 /* seguvs.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = seguvs.c; sourceTree = ""; }; EBC650CB0890C882004FCAA3 /* texpage.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = texpage.c; sourceTree = ""; }; EBC650CD0890C882004FCAA3 /* texture.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = texture.c; sourceTree = ""; }; EBC651900890CEAE004FCAA3 /* button.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = button.c; sourceTree = ""; }; EBC651910890CEAE004FCAA3 /* checkbox.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = checkbox.c; sourceTree = ""; }; EBC651920890CEAE004FCAA3 /* file.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = file.c; sourceTree = ""; }; EBC651940890CEAE004FCAA3 /* gadget.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = gadget.c; sourceTree = ""; }; EBC651960890CEAE004FCAA3 /* icon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = icon.c; sourceTree = ""; }; EBC651970890CEAE004FCAA3 /* inputbox.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = inputbox.c; sourceTree = ""; }; EBC651980890CEAE004FCAA3 /* keypad.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = keypad.c; sourceTree = ""; }; EBC651990890CEAE004FCAA3 /* keypress.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = keypress.c; sourceTree = ""; }; EBC6519A0890CEAE004FCAA3 /* keytrap.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = keytrap.c; sourceTree = ""; }; EBC6519B0890CEAE004FCAA3 /* listbox.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = listbox.c; sourceTree = ""; }; EBC6519E0890CEAE004FCAA3 /* menu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = menu.c; sourceTree = ""; }; EBC6519F0890CEAE004FCAA3 /* menubar.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = menubar.c; sourceTree = ""; }; EBC651A00890CEAE004FCAA3 /* message.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = message.c; sourceTree = ""; }; EBC651A30890CEAE004FCAA3 /* popup.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = popup.c; sourceTree = ""; }; EBC651A40890CEAE004FCAA3 /* radio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = radio.c; sourceTree = ""; }; EBC651A50890CEAE004FCAA3 /* scroll.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = scroll.c; sourceTree = ""; }; EBC651A60890CEAE004FCAA3 /* ui.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ui.c; sourceTree = ""; }; EBC651A70890CEAE004FCAA3 /* uidraw.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = uidraw.c; sourceTree = ""; }; EBC651A80890CEAE004FCAA3 /* userbox.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = userbox.c; sourceTree = ""; }; EBC651A90890CEAE004FCAA3 /* dialog.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = dialog.c; sourceTree = ""; }; EBC652010890D632004FCAA3 /* bmread.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = bmread.c; sourceTree = ""; }; EBC652020890D632004FCAA3 /* dumpmine.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = dumpmine.c; sourceTree = ""; }; EBC6520F0890D6B7004FCAA3 /* ui.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = ""; }; EBC652120890D6DF004FCAA3 /* func.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = func.h; sourceTree = ""; }; EBC858F3122E165800FA437D /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; }; EBCE794C0DE59565008D8F82 /* rbaudio.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = rbaudio.c; sourceTree = ""; }; EBCE79500DE59587008D8F82 /* rbaudio.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = rbaudio.h; sourceTree = ""; }; EBE8D7D00FD385E1009D181F /* gamecntl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamecntl.c; sourceTree = ""; }; EBE8D88F0FDA76D1009D181F /* gamerend.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamerend.c; sourceTree = ""; }; EBEEB0AA0D2A2AEE00FF39B4 /* bitmap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = bitmap.h; sourceTree = ""; }; EBEEB0AB0D2A2AEE00FF39B4 /* clip.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = clip.h; sourceTree = ""; }; EBEEB0B60D2A2B4500FF39B4 /* clipper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = clipper.h; sourceTree = ""; }; EBEEB0B70D2A2B4500FF39B4 /* globvars.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = globvars.h; sourceTree = ""; }; EBEEB1030D2A307300FF39B4 /* scanline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = scanline.h; sourceTree = ""; }; EBEEB1040D2A307300FF39B4 /* texmapl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = texmapl.h; sourceTree = ""; }; EBEEB1150D2A329900FF39B4 /* centers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = centers.h; sourceTree = ""; }; EBEEB1160D2A329900FF39B4 /* editor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = editor.h; sourceTree = ""; }; EBEEB1170D2A329900FF39B4 /* ehostage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ehostage.h; sourceTree = ""; }; EBEEB1180D2A329900FF39B4 /* eobject.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = eobject.h; sourceTree = ""; }; EBEEB1190D2A329900FF39B4 /* eswitch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = eswitch.h; sourceTree = ""; }; EBEEB11A0D2A329900FF39B4 /* info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = info.h; sourceTree = ""; }; EBEEB11B0D2A329900FF39B4 /* kdefs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kdefs.h; sourceTree = ""; }; EBEEB11C0D2A329900FF39B4 /* kfuncs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = kfuncs.h; sourceTree = ""; }; EBEEB11D0D2A329900FF39B4 /* macro.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = macro.h; sourceTree = ""; }; EBEEB11E0D2A329900FF39B4 /* meddraw.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = meddraw.h; sourceTree = ""; }; EBEEB11F0D2A329900FF39B4 /* medlisp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = medlisp.h; sourceTree = ""; }; EBEEB1200D2A329900FF39B4 /* medmisc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = medmisc.h; sourceTree = ""; }; EBEEB1210D2A329900FF39B4 /* medrobot.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = medrobot.h; sourceTree = ""; }; EBEEB1220D2A329900FF39B4 /* medsel.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = medsel.h; sourceTree = ""; }; EBEEB1230D2A329900FF39B4 /* medwall.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = medwall.h; sourceTree = ""; }; EBEEB1240D2A329900FF39B4 /* objpage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = objpage.h; sourceTree = ""; }; EBEEB1250D2A329900FF39B4 /* seguvs.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = seguvs.h; sourceTree = ""; }; EBEEB1260D2A329900FF39B4 /* texpage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = texpage.h; sourceTree = ""; }; EBEEB1BD0D2A423E00FF39B4 /* pstypes.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = pstypes.h; sourceTree = ""; }; EBEEB1E40D2B317700FF39B4 /* custom.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = custom.c; sourceTree = ""; }; EBEEB1E50D2B317700FF39B4 /* custom.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = custom.h; sourceTree = ""; }; EBEEB1F40D2B320B00FF39B4 /* hash.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = ""; }; EBEEB2540D2B35B000FF39B4 /* resource.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = resource.h; sourceTree = ""; }; EBEEB2600D2B364300FF39B4 /* digicomp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = digicomp.c; sourceTree = ""; }; EBEEB2610D2B364300FF39B4 /* digicomp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = digicomp.h; sourceTree = ""; }; EBEEB2680D2B364300FF39B4 /* snddecom.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = snddecom.c; sourceTree = ""; }; EBEEB2690D2B364300FF39B4 /* snddecom.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = snddecom.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 676AC26B0668A938007173EB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 676AC26C0668A938007173EB /* Cocoa.framework in Frameworks */, 6710AB00066B2D6100DB0F68 /* SDL.framework in Frameworks */, EB92BEC60CDD6B4B0045A32C /* SDL_mixer.framework in Frameworks */, EBC858F5122E165800FA437D /* ApplicationServices.framework in Frameworks */, EB91A41112617070009E0095 /* libphysfs.dylib in Frameworks */, EB91A41412617084009E0095 /* libphysfs.dylib in Frameworks */, EB092A4B12A21A14004D9A79 /* Carbon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 676AC31C0668A939007173EB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 6766BAC20668B3A000A6052D /* Cocoa.framework in Frameworks */, 6710AAFF066B2D6100DB0F68 /* SDL.framework in Frameworks */, 6710AB69066B2E0400DB0F68 /* OpenGL.framework in Frameworks */, 17A707EB10C1B5FA002D1680 /* SDL_mixer.framework in Frameworks */, EBC858F4122E165800FA437D /* ApplicationServices.framework in Frameworks */, EB91A41012617070009E0095 /* libphysfs.dylib in Frameworks */, EB91A41312617084009E0095 /* libphysfs.dylib in Frameworks */, EB092A4A12A21A14004D9A79 /* Carbon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; EB775A6D105611320036C348 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( 67F6FED0066B13B400443922 /* SDLMain.h */, 67F6FED1066B13B400443922 /* SDLMain.m */, EBC4BAF6170E62C60033D261 /* tool_bundle.py */, ); name = Classes; sourceTree = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( EB91A41212617084009E0095 /* libphysfs.dylib */, EB91A40F12617070009E0095 /* libphysfs.dylib */, EBC858F3122E165800FA437D /* ApplicationServices.framework */, EB92BEC40CDD6B4B0045A32C /* SDL_mixer.framework */, 6710AB68066B2E0400DB0F68 /* OpenGL.framework */, 6710AAFE066B2D6100DB0F68 /* SDL.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 676AC31D0668A939007173EB /* d1xgl.app */, EB1283BE0D59D94800A991A3 /* d1x.app */, EB775A6F105611320036C348 /* d1Extract */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* d1x */ = { isa = PBXGroup; children = ( 670E3796066C50C30085B671 /* CHANGELOG.txt */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, 675ED123066B196700E42AA7 /* d1x-Info.plist */, 67F6FEEA066B13D900443922 /* d1xgl-Info.plist */, ); name = d1x; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 67B44137066878B300DF26D8 /* 2d */, 67B441740668792300DF26D8 /* 3d */, 67B441EC06687A3F00DF26D8 /* arch */, EBC6507E0890C882004FCAA3 /* editor */, 67B441F806687A9E00DF26D8 /* iff */, 67B448AC0668803500DF26D8 /* include */, 67B446CD06687CF400DF26D8 /* main */, 67B4484806687DCE00DF26D8 /* maths */, 67B4485B06687DFB00DF26D8 /* mem */, 67B4486406687E1000DF26D8 /* misc */, 67B4488506687E5E00DF26D8 /* texmap */, EBC6518D0890CEAE004FCAA3 /* ui */, EB775A77105611720036C348 /* utilities */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( EBAEB74B0BF4A86F00FC6E13 /* d1x-rebirth.icns */, EB380D7B0E168B1900EBD9AD /* InfoPlist.strings */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( EB092A4912A21A14004D9A79 /* Carbon.framework */, 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 676AC04B0668A814007173EB /* ogl */ = { isa = PBXGroup; children = ( 676AC04E0668A814007173EB /* gr.c */, 676AC0510668A814007173EB /* ogl.c */, ); name = ogl; path = arch/ogl; sourceTree = SOURCE_ROOT; }; 67B44137066878B300DF26D8 /* 2d */ = { isa = PBXGroup; children = ( 67B44139066878B300DF26D8 /* 2dsline.c */, 67B4413A066878B300DF26D8 /* bitblt.c */, 67B4413B066878B300DF26D8 /* bitmap.c */, EBEEB0AA0D2A2AEE00FF39B4 /* bitmap.h */, 67B4413D066878B300DF26D8 /* box.c */, 67B4413E066878B300DF26D8 /* canvas.c */, 67B4413F066878B300DF26D8 /* circle.c */, EBEEB0AB0D2A2AEE00FF39B4 /* clip.h */, 67B44141066878B300DF26D8 /* disc.c */, 67B44142066878B300DF26D8 /* font.c */, 67B44143066878B300DF26D8 /* gpixel.c */, 67B44145066878B300DF26D8 /* line.c */, 67B44148066878B300DF26D8 /* palette.c */, 67B44149066878B300DF26D8 /* pcx.c */, 67B4414A066878B300DF26D8 /* pixel.c */, 67B4414B066878B300DF26D8 /* poly.c */, 67B4414C066878B300DF26D8 /* rect.c */, 67B4414D066878B300DF26D8 /* rle.c */, 67B44151066878B300DF26D8 /* scalec.c */, ); path = 2d; sourceTree = SOURCE_ROOT; }; 67B441740668792300DF26D8 /* 3d */ = { isa = PBXGroup; children = ( 67B441760668792300DF26D8 /* clipper.c */, EBEEB0B60D2A2B4500FF39B4 /* clipper.h */, 67B441780668792300DF26D8 /* draw.c */, 67B441790668792300DF26D8 /* globvars.c */, EBEEB0B70D2A2B4500FF39B4 /* globvars.h */, 67B4417B0668792300DF26D8 /* instance.c */, 67B4417D0668792300DF26D8 /* interp.c */, 67B4417F0668792300DF26D8 /* matrix.c */, 67B441800668792300DF26D8 /* points.c */, 67B441810668792300DF26D8 /* rod.c */, 67B441820668792300DF26D8 /* setup.c */, ); path = 3d; sourceTree = SOURCE_ROOT; }; 67B441D106687A0200DF26D8 /* sdl */ = { isa = PBXGroup; children = ( EB92BE5C0CDD693C0045A32C /* digi_audio.c */, EB92BE5D0CDD693C0045A32C /* digi_mixer_music.c */, EB92BE5E0CDD693C0045A32C /* digi_mixer.c */, 67B441D306687A0200DF26D8 /* digi.c */, 67B441D406687A0200DF26D8 /* event.c */, 67B441D506687A0200DF26D8 /* gr.c */, EB28D99B0ECEABD700E68E9B /* init.c */, 67B441D706687A0200DF26D8 /* joy.c */, EB92BE5F0CDD693C0045A32C /* jukebox.c */, 67B441D906687A0200DF26D8 /* key.c */, 67B441DB06687A0200DF26D8 /* mouse.c */, EBCE794C0DE59565008D8F82 /* rbaudio.c */, 67B441DD06687A0200DF26D8 /* timer.c */, EB35ABE00FB199B800C36930 /* window.c */, ); name = sdl; path = arch/sdl; sourceTree = SOURCE_ROOT; }; 67B441EC06687A3F00DF26D8 /* arch */ = { isa = PBXGroup; children = ( EBAFC268088E508D006329AD /* carbon */, EB3319E60D53341900C799B0 /* include */, 676AC04B0668A814007173EB /* ogl */, 67B441D106687A0200DF26D8 /* sdl */, EBEEB24A0D2B35B000FF39B4 /* win32 */, ); name = arch; sourceTree = ""; }; 67B441F806687A9E00DF26D8 /* iff */ = { isa = PBXGroup; children = ( 67B4420006687A9E00DF26D8 /* iff.c */, ); path = iff; sourceTree = SOURCE_ROOT; }; 67B446CD06687CF400DF26D8 /* main */ = { isa = PBXGroup; children = ( 67B446CF06687CF400DF26D8 /* ai.c */, 67B446D206687CF400DF26D8 /* aipath.c */, 67B446D406687CF400DF26D8 /* automap.c */, 67B446D606687CF400DF26D8 /* bm.c */, EBC652010890D632004FCAA3 /* bmread.c */, 67B446DB06687CF400DF26D8 /* cntrlcen.c */, 67B446DD06687CF400DF26D8 /* collide.c */, 67B446E006687CF400DF26D8 /* config.c */, 67B446E206687CF400DF26D8 /* console.c */, 67B446E306687CF400DF26D8 /* controls.c */, 67B446E506687CF400DF26D8 /* credits.c */, EBEEB1E40D2B317700FF39B4 /* custom.c */, EBEEB2600D2B364300FF39B4 /* digicomp.c */, EBAFC28F088E67CD006329AD /* digiobj.c */, EBC652020890D632004FCAA3 /* dumpmine.c */, 67B446F706687CF400DF26D8 /* effects.c */, 67B446F906687CF400DF26D8 /* endlevel.c */, 67B446FD06687CF400DF26D8 /* fireball.c */, 67B446FF06687CF400DF26D8 /* fuelcen.c */, 67B4470106687CF400DF26D8 /* fvi.c */, 67B4470406687CF400DF26D8 /* game.c */, EBE8D7D00FD385E1009D181F /* gamecntl.c */, 67B4470706687CF400DF26D8 /* gamefont.c */, 67B4470906687CF400DF26D8 /* gamemine.c */, EBE8D88F0FDA76D1009D181F /* gamerend.c */, 67B4470E06687CF400DF26D8 /* gamesave.c */, 67B4471006687CF400DF26D8 /* gameseg.c */, 67B4471206687CF400DF26D8 /* gameseq.c */, 67B4471506687CF400DF26D8 /* gauges.c */, 67B4471706687CF400DF26D8 /* hostage.c */, 67B4471906687CF400DF26D8 /* hud.c */, 67B4471B06687CF400DF26D8 /* inferno.c */, 67B4472006687CF400DF26D8 /* kconfig.c */, 676032F9066B39CE008A67A3 /* kmatrix.c */, 67B4472506687CF400DF26D8 /* laser.c */, 67B4472706687CF400DF26D8 /* lighting.c */, 67B4472B06687CF400DF26D8 /* menu.c */, 67B4472D06687CF400DF26D8 /* mglobal.c */, 67B4472E06687CF400DF26D8 /* mission.c */, 67B4473106687CF400DF26D8 /* morph.c */, 676032DC066B399A008A67A3 /* multi.c */, 676032DD066B399A008A67A3 /* multibot.c */, 17DFA6AF10C1A29500674D11 /* net_udp.c */, 67B4473D06687CF400DF26D8 /* newdemo.c */, 67B4473F06687CF400DF26D8 /* newmenu.c */, 67B4474106687CF400DF26D8 /* object.c */, 67B4475906687CF400DF26D8 /* paging.c */, 67B4475B06687CF400DF26D8 /* physics.c */, 67B4475D06687CF400DF26D8 /* piggy.c */, EB8BE84E1071FBE00069486E /* player.c */, 67B4476106687CF400DF26D8 /* playsave.c */, 67B4476306687CF400DF26D8 /* polyobj.c */, 67B4476506687CF400DF26D8 /* powerup.c */, 67B4476706687CF400DF26D8 /* render.c */, 67B4476A06687CF400DF26D8 /* robot.c */, 67B4476C06687CF400DF26D8 /* scores.c */, 67B4477206687CF400DF26D8 /* slew.c */, EBEEB2680D2B364300FF39B4 /* snddecom.c */, 67B4477406687CF400DF26D8 /* songs.c */, 67B4477706687CF400DF26D8 /* state.c */, 67B4477906687CF400DF26D8 /* switch.c */, 67B4477B06687CF400DF26D8 /* terrain.c */, 67B4477D06687CF400DF26D8 /* texmerge.c */, 67B4477F06687CF500DF26D8 /* text.c */, 67B4478206687CF500DF26D8 /* titles.c */, 67B4478406687CF500DF26D8 /* vclip.c */, EBC4BAF9170E63E90033D261 /* vers_id.c */, 67B4478706687CF500DF26D8 /* wall.c */, 67B4478906687CF500DF26D8 /* weapon.c */, EB0421040A341042002CC961 /* ai.h */, EB0421010A341042002CC961 /* aistruct.h */, EB0421030A341042002CC961 /* automap.h */, EB0421020A341042002CC961 /* bm.h */, EB0420F10A341042002CC961 /* collide.h */, EB0421060A341042002CC961 /* config.h */, EB0421050A341042002CC961 /* controls.h */, EB0420BF0A341042002CC961 /* cntrlcen.h */, EB0420E50A341042002CC961 /* credits.h */, EBEEB2610D2B364300FF39B4 /* digicomp.h */, EBEEB1E50D2B317700FF39B4 /* custom.h */, EB0420E10A341042002CC961 /* digi.h */, EB0421000A341042002CC961 /* effects.h */, EB0420FF0A341042002CC961 /* endlevel.h */, EB0420FD0A341042002CC961 /* fireball.h */, EB0420F00A341042002CC961 /* fuelcen.h */, EB0420EF0A341042002CC961 /* fvi.h */, EB0420ED0A341042002CC961 /* game.h */, EB0420EC0A341042002CC961 /* gamefont.h */, EB0420EB0A341042002CC961 /* gamemine.h */, EB0420E90A341042002CC961 /* gamesave.h */, EB0420E80A341042002CC961 /* gameseg.h */, EB0420E30A341042002CC961 /* gameseq.h */, EB0420F80A341042002CC961 /* gauges.h */, EBEEB1F40D2B320B00FF39B4 /* hash.h */, EB0420F70A341042002CC961 /* hostage.h */, EB0420F60A341042002CC961 /* hudmsg.h */, EB0420F50A341042002CC961 /* inferno.h */, EB0420F30A341042002CC961 /* kconfig.h */, EB0420F20A341042002CC961 /* kmatrix.h */, EB0420FC0A341042002CC961 /* laser.h */, EB0420FA0A341042002CC961 /* lighting.h */, EB0420BE0A341042002CC961 /* menu.h */, EB0420BD0A341042002CC961 /* mission.h */, EB0420BB0A341042002CC961 /* morph.h */, EB0420B90A341041002CC961 /* multi.h */, EB0420E70A341042002CC961 /* multibot.h */, 17DFA6B210C1A2A300674D11 /* net_udp.h */, EB01AFA90A65323200EA4C7C /* newdemo.h */, EB0420DE0A341042002CC961 /* newmenu.h */, EB0420DD0A341042002CC961 /* object.h */, EB0420DC0A341042002CC961 /* paging.h */, EB0420DB0A341042002CC961 /* physics.h */, EB0420DA0A341042002CC961 /* piggy.h */, EB0420D90A341042002CC961 /* player.h */, EB0420D80A341042002CC961 /* playsave.h */, EB0420D70A341042002CC961 /* polyobj.h */, EB0420D60A341042002CC961 /* powerup.h */, EB0420D50A341042002CC961 /* render.h */, EB0420D30A341042002CC961 /* robot.h */, EB0420D20A341042002CC961 /* scores.h */, EB0420D10A341042002CC961 /* screens.h */, EB0420D00A341042002CC961 /* segment.h */, EB0420CF0A341042002CC961 /* segpoint.h */, EB0420CE0A341042002CC961 /* slew.h */, EBEEB2690D2B364300FF39B4 /* snddecom.h */, EB0420CD0A341042002CC961 /* songs.h */, EB0420CC0A341042002CC961 /* sounds.h */, EB0420CB0A341042002CC961 /* state.h */, EB0420CA0A341042002CC961 /* switch.h */, EB0420C90A341042002CC961 /* terrain.h */, EB0420C80A341042002CC961 /* texmerge.h */, EB0420C70A341042002CC961 /* text.h */, EB0420C60A341042002CC961 /* textures.h */, EB0420C50A341042002CC961 /* titles.h */, EB0420C40A341042002CC961 /* vclip.h */, EB0420C30A341042002CC961 /* vers_id.h */, EB0420C20A341042002CC961 /* wall.h */, EB0420C10A341042002CC961 /* weapon.h */, ); path = main; sourceTree = SOURCE_ROOT; }; 67B4484806687DCE00DF26D8 /* maths */ = { isa = PBXGroup; children = ( 67B4484B06687DCE00DF26D8 /* fixc.c */, 67B4484D06687DCE00DF26D8 /* rand.c */, 67B4484E06687DCE00DF26D8 /* tables.c */, 67B4484F06687DCE00DF26D8 /* vecmat.c */, ); path = maths; sourceTree = SOURCE_ROOT; }; 67B4485B06687DFB00DF26D8 /* mem */ = { isa = PBXGroup; children = ( 67B4485E06687DFB00DF26D8 /* mem.c */, ); path = mem; sourceTree = SOURCE_ROOT; }; 67B4486406687E1000DF26D8 /* misc */ = { isa = PBXGroup; children = ( EBC58E700D489E19007C8ABF /* args.c */, EB92BEA40CDD6A570045A32C /* dl_list.c */, 67B4486A06687E1000DF26D8 /* error.c */, EBC4BAFC170E64760033D261 /* hash.c */, 179E6E9D11F37B3400175C54 /* hmp.c */, EBAC98F90D42497F0017D4BC /* ignorecase.c */, EB1405B912100883002B1CC6 /* physfsx.c */, 67B4487206687E1000DF26D8 /* strio.c */, 67B4487306687E1000DF26D8 /* strutil.c */, ); path = misc; sourceTree = SOURCE_ROOT; }; 67B4488506687E5E00DF26D8 /* texmap */ = { isa = PBXGroup; children = ( 67B4488806687E5E00DF26D8 /* ntmap.c */, 67B4488906687E5E00DF26D8 /* scanline.c */, EBEEB1030D2A307300FF39B4 /* scanline.h */, EBEEB1040D2A307300FF39B4 /* texmapl.h */, 67B4489206687E5E00DF26D8 /* tmapflat.c */, ); path = texmap; sourceTree = SOURCE_ROOT; }; 67B448AC0668803500DF26D8 /* include */ = { isa = PBXGroup; children = ( EBEEB1140D2A329900FF39B4 /* editor */, 6791CF8D066888DD00056A5A /* 3d.h */, 6791D00B066889CD00056A5A /* args.h */, 6791CE4F0668852C00056A5A /* byteswap.h */, EB9181090DABA47B0010CB39 /* console.h */, EB92BE680CDD69830045A32C /* dl_list.h */, EBC4BAF4170E62160033D261 /* dxxerror.h */, 6791CF420668881F00056A5A /* fix.h */, EBC652120890D6DF004FCAA3 /* func.h */, 67B44914066880C400DF26D8 /* gr.h */, 67B44915066880C400DF26D8 /* grdef.h */, 179E6E9A11F37B2400175C54 /* hmp.h */, 6791D0BD06688AE800056A5A /* iff.h */, EBAC994E0D4250320017D4BC /* ignorecase.h */, EB3319F00D5334B600C799B0 /* internal.h */, EB3319F10D53351600C799B0 /* loadgl.h */, EBC4BAF5170E62160033D261 /* makesig.h */, 6791D08F06688A9C00056A5A /* maths.h */, EB3319F20D53351600C799B0 /* ogl_init.h */, 6791CF4E0668883900056A5A /* palette.h */, 6791CF620668885500056A5A /* pcx.h */, EBAC99500D4250320017D4BC /* physfsx.h */, EBEEB1BD0D2A423E00FF39B4 /* pstypes.h */, EBCE79500DE59587008D8F82 /* rbaudio.h */, 6791CE500668852C00056A5A /* rle.h */, 6791D1550668903B00056A5A /* strio.h */, 6791D0A306688AB900056A5A /* strutil.h */, 6791CFB10668891200056A5A /* texmap.h */, 6791D04B06688A2E00056A5A /* timer.h */, EBC6520F0890D6B7004FCAA3 /* ui.h */, 67B4490F066880A300DF26D8 /* u_mem.h */, 6791D026066889F100056A5A /* vecmat.h */, ); path = include; sourceTree = SOURCE_ROOT; }; EB3319E60D53341900C799B0 /* include */ = { isa = PBXGroup; children = ( EB3319E70D53341900C799B0 /* digi_audio.h */, EB3319E80D53341900C799B0 /* digi_mixer.h */, EB3319E90D53341900C799B0 /* digi_mixer_music.h */, EB3319EA0D53341900C799B0 /* event.h */, EB3319EB0D53341900C799B0 /* joy.h */, EB3319ED0D53341900C799B0 /* jukebox.h */, EB3319EE0D53341900C799B0 /* key.h */, EB0929F712A10889004D9A79 /* messagebox.h */, EB3319EF0D53341900C799B0 /* mouse.h */, EB35ABDF0FB199B800C36930 /* window.h */, ); name = include; path = arch/include; sourceTree = ""; }; EB6142441501EDC9004E2AE8 /* data */ = { isa = PBXGroup; children = ( EB6142451501EDC9004E2AE8 /* curve.pad */, EB6142461501EDC9004E2AE8 /* dummy.pad */, EB6142471501EDC9004E2AE8 /* group.pad */, EB6142481501EDC9004E2AE8 /* lighting.pad */, EB6142491501EDC9004E2AE8 /* med.mnu */, EB61424A1501EDC9004E2AE8 /* newobj.pad */, EB61424B1501EDC9004E2AE8 /* object.pad */, EB61424C1501EDC9004E2AE8 /* objmov.pad */, EB61424D1501EDC9004E2AE8 /* pc6x8.fnt */, EB61424E1501EDC9004E2AE8 /* pc8x16.fnt */, EB61424F1501EDC9004E2AE8 /* segmove.pad */, EB6142501501EDC9004E2AE8 /* segsize.pad */, EB6142511501EDC9004E2AE8 /* test.pad */, EB6142521501EDC9004E2AE8 /* texture.pad */, ); path = data; sourceTree = ""; }; EB775A77105611720036C348 /* utilities */ = { isa = PBXGroup; children = ( EB775A79105611720036C348 /* extractD1Data.cpp */, ); path = utilities; sourceTree = ""; }; EBAFC268088E508D006329AD /* carbon */ = { isa = PBXGroup; children = ( EBAFC269088E508D006329AD /* conf.h */, EB0929F812A10889004D9A79 /* messagebox.c */, EBAFC26A088E508D006329AD /* descent.r */, EBAFC26D088E508D006329AD /* SDL_main.c */, ); name = carbon; path = arch/carbon; sourceTree = ""; }; EBC6507E0890C882004FCAA3 /* editor */ = { isa = PBXGroup; children = ( EBC650800890C882004FCAA3 /* autosave.c */, EB6142441501EDC9004E2AE8 /* data */, EBC650970890C882004FCAA3 /* centers.c */, EBC650990890C882004FCAA3 /* curves.c */, EBC6509B0890C882004FCAA3 /* eglobal.c */, EBC6509C0890C882004FCAA3 /* ehostage.c */, EBC6509E0890C882004FCAA3 /* elight.c */, EBC6509F0890C882004FCAA3 /* eobject.c */, EBC650A10890C882004FCAA3 /* eswitch.c */, EBC650A30890C882004FCAA3 /* fixseg.c */, EBC650A40890C882004FCAA3 /* func.c */, EBC650A50890C882004FCAA3 /* group.c */, EBC650A60890C882004FCAA3 /* info.c */, EBC650A80890C882004FCAA3 /* kbuild.c */, EBC650A90890C882004FCAA3 /* kcurve.c */, EBC650AB0890C882004FCAA3 /* kfuncs.c */, EBC650AD0890C882004FCAA3 /* kgame.c */, EBC650AF0890C882004FCAA3 /* khelp.c */, EBC650B00890C882004FCAA3 /* kmine.c */, EBC650B10890C882004FCAA3 /* ksegmove.c */, EBC650B20890C882004FCAA3 /* ksegsel.c */, EBC650B30890C882004FCAA3 /* ksegsize.c */, EBC650B40890C882004FCAA3 /* ktmap.c */, EBC650B50890C882004FCAA3 /* kview.c */, EBC650B90890C882004FCAA3 /* med.c */, EBC650BA0890C882004FCAA3 /* meddraw.c */, EBC650BD0890C882004FCAA3 /* medmisc.c */, EBC650BF0890C882004FCAA3 /* medrobot.c */, EBC650C10890C882004FCAA3 /* medsel.c */, EBC650C30890C882004FCAA3 /* medwall.c */, EBC650C50890C882004FCAA3 /* mine.c */, EBC650C60890C882004FCAA3 /* objpage.c */, EBC650C80890C882004FCAA3 /* segment.c */, EBC650C90890C882004FCAA3 /* seguvs.c */, EBC650CB0890C882004FCAA3 /* texpage.c */, EBC650CD0890C882004FCAA3 /* texture.c */, ); path = editor; sourceTree = ""; }; EBC6518D0890CEAE004FCAA3 /* ui */ = { isa = PBXGroup; children = ( EBC651900890CEAE004FCAA3 /* button.c */, EBC651910890CEAE004FCAA3 /* checkbox.c */, EBC651920890CEAE004FCAA3 /* file.c */, EBC651940890CEAE004FCAA3 /* gadget.c */, EBC651960890CEAE004FCAA3 /* icon.c */, EBC651970890CEAE004FCAA3 /* inputbox.c */, EBC651980890CEAE004FCAA3 /* keypad.c */, EBC651990890CEAE004FCAA3 /* keypress.c */, EBC6519A0890CEAE004FCAA3 /* keytrap.c */, EBC6519B0890CEAE004FCAA3 /* listbox.c */, EBC6519E0890CEAE004FCAA3 /* menu.c */, EBC6519F0890CEAE004FCAA3 /* menubar.c */, EBC651A00890CEAE004FCAA3 /* message.c */, EBC651A30890CEAE004FCAA3 /* popup.c */, EBC651A40890CEAE004FCAA3 /* radio.c */, EBC651A50890CEAE004FCAA3 /* scroll.c */, EBC651A60890CEAE004FCAA3 /* ui.c */, EBC651A70890CEAE004FCAA3 /* uidraw.c */, EBC651A80890CEAE004FCAA3 /* userbox.c */, EBC651A90890CEAE004FCAA3 /* dialog.c */, ); path = ui; sourceTree = ""; }; EBEEB1140D2A329900FF39B4 /* editor */ = { isa = PBXGroup; children = ( EBEEB1150D2A329900FF39B4 /* centers.h */, EBEEB1160D2A329900FF39B4 /* editor.h */, EBEEB1170D2A329900FF39B4 /* ehostage.h */, EBEEB1180D2A329900FF39B4 /* eobject.h */, EBC4BAF8170E63890033D261 /* esegment.h */, EBEEB1190D2A329900FF39B4 /* eswitch.h */, EBEEB11A0D2A329900FF39B4 /* info.h */, EBEEB11B0D2A329900FF39B4 /* kdefs.h */, EBEEB11C0D2A329900FF39B4 /* kfuncs.h */, EBEEB11D0D2A329900FF39B4 /* macro.h */, EBEEB11E0D2A329900FF39B4 /* meddraw.h */, EBEEB11F0D2A329900FF39B4 /* medlisp.h */, EBEEB1200D2A329900FF39B4 /* medmisc.h */, EBEEB1210D2A329900FF39B4 /* medrobot.h */, EBEEB1220D2A329900FF39B4 /* medsel.h */, EBEEB1230D2A329900FF39B4 /* medwall.h */, EBEEB1240D2A329900FF39B4 /* objpage.h */, EBEEB1250D2A329900FF39B4 /* seguvs.h */, EBEEB1260D2A329900FF39B4 /* texpage.h */, ); path = editor; sourceTree = ""; }; EBEEB24A0D2B35B000FF39B4 /* win32 */ = { isa = PBXGroup; children = ( EBC4BAF7170E63380033D261 /* d1x-rebirth.rc */, EB092A3A12A21527004D9A79 /* messagebox.c */, EBEEB24F0D2B35B000FF39B4 /* include */, ); name = win32; path = arch/win32; sourceTree = ""; }; EBEEB24F0D2B35B000FF39B4 /* include */ = { isa = PBXGroup; children = ( EBEEB2540D2B35B000FF39B4 /* resource.h */, ); path = include; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 676AC1C00668A938007173EB /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 676AC1C20668A938007173EB /* u_mem.h in Headers */, 676AC1C40668A938007173EB /* gr.h in Headers */, 676AC1C50668A938007173EB /* grdef.h in Headers */, 676AC1C70668A938007173EB /* byteswap.h in Headers */, 676AC1C80668A938007173EB /* rle.h in Headers */, 676AC1CE0668A938007173EB /* fix.h in Headers */, 676AC1CF0668A938007173EB /* palette.h in Headers */, 676AC1D00668A938007173EB /* pcx.h in Headers */, 676AC1D10668A938007173EB /* 3d.h in Headers */, 676AC1D20668A938007173EB /* texmap.h in Headers */, 676AC1D70668A938007173EB /* args.h in Headers */, 676AC1D90668A938007173EB /* vecmat.h in Headers */, 676AC1DA0668A938007173EB /* timer.h in Headers */, 676AC1DE0668A938007173EB /* maths.h in Headers */, 676AC1E00668A938007173EB /* strutil.h in Headers */, 676AC1E10668A938007173EB /* iff.h in Headers */, 676AC1E50668A938007173EB /* strio.h in Headers */, 67F6FED2066B13B400443922 /* SDLMain.h in Headers */, EBAFC26E088E508D006329AD /* conf.h in Headers */, EBC652100890D6B7004FCAA3 /* ui.h in Headers */, EBC652130890D6DF004FCAA3 /* func.h in Headers */, EBEEB0B20D2A2AEF00FF39B4 /* bitmap.h in Headers */, EBEEB0B30D2A2AEF00FF39B4 /* clip.h in Headers */, EBEEB0BA0D2A2B4500FF39B4 /* clipper.h in Headers */, EBEEB0BB0D2A2B4500FF39B4 /* globvars.h in Headers */, EBEEB1070D2A307300FF39B4 /* scanline.h in Headers */, EBEEB1080D2A307300FF39B4 /* texmapl.h in Headers */, EBEEB1EA0D2B317800FF39B4 /* custom.h in Headers */, EBEEB2000D2B320C00FF39B4 /* hash.h in Headers */, EB35ABE30FB199B800C36930 /* window.h in Headers */, EB0929FB12A10889004D9A79 /* messagebox.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 676AC2720668A939007173EB /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 676AC2770668A939007173EB /* 3d.h in Headers */, 676AC2780668A939007173EB /* args.h in Headers */, 676AC2790668A939007173EB /* byteswap.h in Headers */, 676AC2800668A939007173EB /* fix.h in Headers */, 676AC2810668A939007173EB /* gr.h in Headers */, 676AC2820668A939007173EB /* grdef.h in Headers */, 676AC2850668A939007173EB /* iff.h in Headers */, 676AC2890668A939007173EB /* maths.h in Headers */, 676AC28C0668A939007173EB /* pcx.h in Headers */, 676AC28D0668A939007173EB /* palette.h in Headers */, 676AC2900668A939007173EB /* rle.h in Headers */, 676AC2910668A939007173EB /* strio.h in Headers */, 676AC2920668A939007173EB /* strutil.h in Headers */, 676AC2930668A939007173EB /* texmap.h in Headers */, 676AC2940668A939007173EB /* timer.h in Headers */, 676AC2960668A939007173EB /* u_mem.h in Headers */, 676AC2970668A939007173EB /* vecmat.h in Headers */, 67F6FED4066B13B400443922 /* SDLMain.h in Headers */, EBAFC2C0088E6BC7006329AD /* conf.h in Headers */, EBC652110890D6B7004FCAA3 /* ui.h in Headers */, EBC652140890D6DF004FCAA3 /* func.h in Headers */, EBEEB0AE0D2A2AEE00FF39B4 /* bitmap.h in Headers */, EBEEB0AF0D2A2AEE00FF39B4 /* clip.h in Headers */, EBEEB0B80D2A2B4500FF39B4 /* clipper.h in Headers */, EBEEB0B90D2A2B4500FF39B4 /* globvars.h in Headers */, EBEEB1050D2A307300FF39B4 /* scanline.h in Headers */, EBEEB1060D2A307300FF39B4 /* texmapl.h in Headers */, EBEEB1EF0D2B317800FF39B4 /* custom.h in Headers */, EBEEB20C0D2B320C00FF39B4 /* hash.h in Headers */, EB35ABE10FB199B800C36930 /* window.h in Headers */, EB0929F912A10889004D9A79 /* messagebox.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 676AC1BF0668A938007173EB /* d1x */ = { isa = PBXNativeTarget; buildConfigurationList = EBBAD4920B2D0F7E00080BBF /* Build configuration list for PBXNativeTarget "d1x" */; buildPhases = ( 676AC1C00668A938007173EB /* Headers */, 676AC1E80668A938007173EB /* Resources */, 676AC1EA0668A938007173EB /* Sources */, 676AC26B0668A938007173EB /* Frameworks */, EB6142761501EFAB004E2AE8 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = d1x; productInstallPath = "$(HOME)/Applications"; productName = d1x; productReference = EB1283BE0D59D94800A991A3 /* d1x.app */; productType = "com.apple.product-type.application"; }; 676AC2710668A939007173EB /* d1xgl */ = { isa = PBXNativeTarget; buildConfigurationList = EBBAD4960B2D0F7E00080BBF /* Build configuration list for PBXNativeTarget "d1xgl" */; buildPhases = ( 676AC2720668A939007173EB /* Headers */, 676AC29A0668A939007173EB /* Resources */, 676AC29B0668A939007173EB /* Sources */, 676AC31C0668A939007173EB /* Frameworks */, EBAC9A701525C67500F6C779 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = d1xgl; productName = d1xgl; productReference = 676AC31D0668A939007173EB /* d1xgl.app */; productType = "com.apple.product-type.application"; }; EB775A6E105611320036C348 /* d1Extract */ = { isa = PBXNativeTarget; buildConfigurationList = EB775A76105611690036C348 /* Build configuration list for PBXNativeTarget "d1Extract" */; buildPhases = ( EB775A6C105611320036C348 /* Sources */, EB775A6D105611320036C348 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = d1Extract; productName = d1Extract; productReference = EB775A6F105611320036C348 /* d1Extract */; productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = EBBAD49E0B2D0F7E00080BBF /* Build configuration list for PBXProject "d1x-rebirth" */; compatibilityVersion = "Xcode 2.4"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* d1x */; projectDirPath = ""; projectRoot = ""; targets = ( 676AC1BF0668A938007173EB /* d1x */, 676AC2710668A939007173EB /* d1xgl */, EB775A6E105611320036C348 /* d1Extract */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 676AC1E80668A938007173EB /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 675ED149066B198A00E42AA7 /* d1x-Info.plist in Resources */, EB9E8DF30D66C2570099B0B5 /* d1x-rebirth.icns in Resources */, EB380D7E0E168B1900EBD9AD /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 676AC29A0668A939007173EB /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( EB61427E1501F2FB004E2AE8 /* d1xgl-Info.plist in Resources */, EBAEB74C0BF4A86F00FC6E13 /* d1x-rebirth.icns in Resources */, EB380D7D0E168B1900EBD9AD /* InfoPlist.strings in Resources */, EBAC9A3D1525C5E800F6C779 /* curve.pad in Resources */, EBAC9A3E1525C5E800F6C779 /* dummy.pad in Resources */, EBAC9A3F1525C5E800F6C779 /* group.pad in Resources */, EBAC9A401525C5E800F6C779 /* lighting.pad in Resources */, EBAC9A411525C5E800F6C779 /* med.mnu in Resources */, EBAC9A421525C5E800F6C779 /* newobj.pad in Resources */, EBAC9A431525C5E800F6C779 /* object.pad in Resources */, EBAC9A441525C5E800F6C779 /* objmov.pad in Resources */, EBAC9A451525C5E800F6C779 /* pc6x8.fnt in Resources */, EBAC9A461525C5E800F6C779 /* pc8x16.fnt in Resources */, EBAC9A471525C5E800F6C779 /* segmove.pad in Resources */, EBAC9A481525C5E800F6C779 /* segsize.pad in Resources */, EBAC9A491525C5E800F6C779 /* test.pad in Resources */, EBAC9A4A1525C5E800F6C779 /* texture.pad in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 676AC1EA0668A938007173EB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 67F6FED3066B13B400443922 /* SDLMain.m in Sources */, 676AC1EC0668A938007173EB /* 2dsline.c in Sources */, 676AC1ED0668A938007173EB /* bitblt.c in Sources */, 676AC1EE0668A938007173EB /* bitmap.c in Sources */, 676AC1EF0668A938007173EB /* box.c in Sources */, 676AC1F00668A938007173EB /* canvas.c in Sources */, 676AC1F10668A938007173EB /* circle.c in Sources */, 676AC1F20668A938007173EB /* disc.c in Sources */, 676AC1F30668A938007173EB /* font.c in Sources */, 676AC1F40668A938007173EB /* gpixel.c in Sources */, 676AC1F60668A938007173EB /* line.c in Sources */, 676AC1F70668A938007173EB /* palette.c in Sources */, 676AC1F80668A938007173EB /* pcx.c in Sources */, 676AC1F90668A938007173EB /* pixel.c in Sources */, 676AC1FA0668A938007173EB /* poly.c in Sources */, 676AC1FB0668A938007173EB /* rect.c in Sources */, 676AC1FC0668A938007173EB /* rle.c in Sources */, 676AC1FD0668A938007173EB /* scalec.c in Sources */, 676AC1FF0668A938007173EB /* clipper.c in Sources */, 676AC2000668A938007173EB /* draw.c in Sources */, 676AC2010668A938007173EB /* globvars.c in Sources */, 676AC2020668A938007173EB /* instance.c in Sources */, 676AC2030668A938007173EB /* interp.c in Sources */, 676AC2040668A938007173EB /* matrix.c in Sources */, 676AC2050668A938007173EB /* points.c in Sources */, 676AC2060668A938007173EB /* rod.c in Sources */, 676AC2070668A938007173EB /* setup.c in Sources */, 676AC20A0668A938007173EB /* digi.c in Sources */, 676AC20B0668A938007173EB /* event.c in Sources */, 676AC20C0668A938007173EB /* gr.c in Sources */, 676AC20E0668A938007173EB /* joy.c in Sources */, 676AC2100668A938007173EB /* key.c in Sources */, 676AC2110668A938007173EB /* mouse.c in Sources */, 676AC2130668A938007173EB /* timer.c in Sources */, 676AC2150668A938007173EB /* iff.c in Sources */, 676AC2160668A938007173EB /* ai.c in Sources */, 676AC2180668A938007173EB /* aipath.c in Sources */, 676AC2190668A938007173EB /* automap.c in Sources */, 676AC21A0668A938007173EB /* bm.c in Sources */, EBC652030890D632004FCAA3 /* bmread.c in Sources */, 676AC21C0668A938007173EB /* cntrlcen.c in Sources */, 676AC21D0668A938007173EB /* collide.c in Sources */, 676AC21E0668A938007173EB /* config.c in Sources */, 676AC21F0668A938007173EB /* console.c in Sources */, 676AC2200668A938007173EB /* controls.c in Sources */, 676AC2210668A938007173EB /* credits.c in Sources */, EBAFC290088E67CD006329AD /* digiobj.c in Sources */, EBC652040890D632004FCAA3 /* dumpmine.c in Sources */, 676AC2230668A938007173EB /* effects.c in Sources */, 676AC2240668A938007173EB /* endlevel.c in Sources */, 676AC2260668A938007173EB /* fireball.c in Sources */, 676AC2270668A938007173EB /* fuelcen.c in Sources */, 676AC2280668A938007173EB /* fvi.c in Sources */, 676AC2290668A938007173EB /* game.c in Sources */, 676AC22B0668A938007173EB /* gamefont.c in Sources */, 676AC22C0668A938007173EB /* gamemine.c in Sources */, 676AC22F0668A938007173EB /* gamesave.c in Sources */, 676AC2300668A938007173EB /* gameseg.c in Sources */, 676AC2310668A938007173EB /* gameseq.c in Sources */, 676AC2320668A938007173EB /* gauges.c in Sources */, 676AC2330668A938007173EB /* hostage.c in Sources */, 676AC2340668A938007173EB /* hud.c in Sources */, 676AC2350668A938007173EB /* inferno.c in Sources */, 676AC2360668A938007173EB /* kconfig.c in Sources */, 676032FB066B39CE008A67A3 /* kmatrix.c in Sources */, 676AC2380668A938007173EB /* laser.c in Sources */, 676AC2390668A938007173EB /* lighting.c in Sources */, 676AC23A0668A938007173EB /* menu.c in Sources */, 676AC23B0668A938007173EB /* mglobal.c in Sources */, 676AC23C0668A938007173EB /* mission.c in Sources */, 676AC23D0668A938007173EB /* morph.c in Sources */, 676032E4066B399A008A67A3 /* multi.c in Sources */, 676032E5066B399A008A67A3 /* multibot.c in Sources */, 676AC23F0668A938007173EB /* newdemo.c in Sources */, 676AC2400668A938007173EB /* newmenu.c in Sources */, 676AC2410668A938007173EB /* object.c in Sources */, 676AC2420668A938007173EB /* paging.c in Sources */, 676AC2430668A938007173EB /* physics.c in Sources */, 676AC2440668A938007173EB /* piggy.c in Sources */, 676AC2460668A938007173EB /* playsave.c in Sources */, 676AC2470668A938007173EB /* polyobj.c in Sources */, 676AC2480668A938007173EB /* powerup.c in Sources */, 676AC2490668A938007173EB /* render.c in Sources */, 676AC24A0668A938007173EB /* robot.c in Sources */, 676AC24B0668A938007173EB /* scores.c in Sources */, 676AC24D0668A938007173EB /* slew.c in Sources */, 676AC24E0668A938007173EB /* songs.c in Sources */, 676AC24F0668A938007173EB /* state.c in Sources */, 676AC2500668A938007173EB /* switch.c in Sources */, 676AC2510668A938007173EB /* terrain.c in Sources */, 676AC2520668A938007173EB /* texmerge.c in Sources */, 676AC2530668A938007173EB /* text.c in Sources */, 676AC2540668A938007173EB /* titles.c in Sources */, 676AC2550668A938007173EB /* vclip.c in Sources */, 676AC2560668A938007173EB /* wall.c in Sources */, 676AC2570668A938007173EB /* weapon.c in Sources */, 676AC2580668A938007173EB /* fixc.c in Sources */, 676AC2590668A938007173EB /* rand.c in Sources */, 676AC25A0668A938007173EB /* tables.c in Sources */, 676AC25B0668A938007173EB /* vecmat.c in Sources */, 676AC25C0668A938007173EB /* mem.c in Sources */, 676AC25F0668A938007173EB /* error.c in Sources */, 676AC2610668A938007173EB /* strio.c in Sources */, 676AC2620668A938007173EB /* strutil.c in Sources */, 676AC2630668A938007173EB /* ntmap.c in Sources */, 676AC2640668A938007173EB /* scanline.c in Sources */, 676AC2650668A938007173EB /* tmapflat.c in Sources */, EB92BE640CDD693C0045A32C /* digi_audio.c in Sources */, EB92BE650CDD693C0045A32C /* digi_mixer_music.c in Sources */, EB92BE660CDD693C0045A32C /* digi_mixer.c in Sources */, EB92BE670CDD693C0045A32C /* jukebox.c in Sources */, EB92BEA80CDD6A570045A32C /* dl_list.c in Sources */, EBEEB1E90D2B317800FF39B4 /* custom.c in Sources */, EBAC98FD0D42497F0017D4BC /* ignorecase.c in Sources */, EBC58E720D489E19007C8ABF /* args.c in Sources */, EB331A0C0D53578800C799B0 /* snddecom.c in Sources */, EBCE794D0DE59565008D8F82 /* rbaudio.c in Sources */, EB28D99D0ECEABD700E68E9B /* init.c in Sources */, EB35ABE40FB199B800C36930 /* window.c in Sources */, EBE8D7D20FD385E1009D181F /* gamecntl.c in Sources */, EBE8D8910FDA76D1009D181F /* gamerend.c in Sources */, EB8BE8501071FBE00069486E /* player.c in Sources */, 17DFA6B110C1A29500674D11 /* net_udp.c in Sources */, 179E6E9E11F37B3400175C54 /* hmp.c in Sources */, EB1405BB12100883002B1CC6 /* physfsx.c in Sources */, EB0929FC12A10889004D9A79 /* messagebox.c in Sources */, EBECB64212C040EB00D660B3 /* autosave.c in Sources */, EBECB64312C040EC00D660B3 /* centers.c in Sources */, EBECB64412C040ED00D660B3 /* curves.c in Sources */, EBECB64512C040EE00D660B3 /* eglobal.c in Sources */, EBECB64612C040F400D660B3 /* ehostage.c in Sources */, EBECB64712C040F500D660B3 /* elight.c in Sources */, EBECB64812C040F600D660B3 /* eobject.c in Sources */, EBECB64912C040F800D660B3 /* eswitch.c in Sources */, EBECB64A12C040FC00D660B3 /* fixseg.c in Sources */, EBECB64B12C0410000D660B3 /* func.c in Sources */, EBECB64C12C0410200D660B3 /* group.c in Sources */, EBECB64D12C0410500D660B3 /* info.c in Sources */, EBECB64E12C0410900D660B3 /* kbuild.c in Sources */, EBECB64F12C0410E00D660B3 /* kcurve.c in Sources */, EBECB65012C0411000D660B3 /* kfuncs.c in Sources */, EBECB65112C0411400D660B3 /* kgame.c in Sources */, EBECB65212C0411900D660B3 /* khelp.c in Sources */, EBECB65312C0411B00D660B3 /* kmine.c in Sources */, EBECB65412C0411F00D660B3 /* ksegmove.c in Sources */, EBECB65512C0412000D660B3 /* ksegsel.c in Sources */, EBECB65612C0412200D660B3 /* ksegsize.c in Sources */, EBECB65712C0412400D660B3 /* ktmap.c in Sources */, EBECB65812C0412600D660B3 /* kview.c in Sources */, EBECB65A12C0413800D660B3 /* med.c in Sources */, EBECB65B12C0413C00D660B3 /* meddraw.c in Sources */, EBECB65C12C0414100D660B3 /* medmisc.c in Sources */, EBECB65D12C0414D00D660B3 /* medrobot.c in Sources */, EBECB65E12C0415100D660B3 /* medsel.c in Sources */, EBECB65F12C0415200D660B3 /* medwall.c in Sources */, EBECB66012C0415400D660B3 /* mine.c in Sources */, EBECB66112C0415E00D660B3 /* objpage.c in Sources */, EBECB66212C0416000D660B3 /* segment.c in Sources */, EBECB66312C0416400D660B3 /* seguvs.c in Sources */, EBECB66412C0416500D660B3 /* texpage.c in Sources */, EBECB66512C0416600D660B3 /* texture.c in Sources */, EBECB66612C0416F00D660B3 /* button.c in Sources */, EBECB66712C0417300D660B3 /* checkbox.c in Sources */, EBECB66812C0417500D660B3 /* gadget.c in Sources */, EBECB66912C0417700D660B3 /* icon.c in Sources */, EBECB66A12C0417D00D660B3 /* inputbox.c in Sources */, EBECB66B12C0418500D660B3 /* keypad.c in Sources */, EBECB66C12C0418600D660B3 /* keypress.c in Sources */, EBECB66D12C0418700D660B3 /* keytrap.c in Sources */, EBECB66F12C0418F00D660B3 /* listbox.c in Sources */, EBECB67012C041C100D660B3 /* menu.c in Sources */, EBECB67112C041C700D660B3 /* menubar.c in Sources */, EBECB67212C041CD00D660B3 /* message.c in Sources */, EBECB67412C041D200D660B3 /* popup.c in Sources */, EBECB67512C041D500D660B3 /* radio.c in Sources */, EBECB67612C041DC00D660B3 /* scroll.c in Sources */, EBECB67712C041E500D660B3 /* ui.c in Sources */, EBECB67812C041E800D660B3 /* uidraw.c in Sources */, EBECB67912C041EA00D660B3 /* userbox.c in Sources */, EBECB67A12C041EB00D660B3 /* dialog.c in Sources */, EB2C86E612C36FFB0073E30E /* file.c in Sources */, EBC4BAFA170E64540033D261 /* vers_id.c in Sources */, EBC4BB11170E660B0033D261 /* hash.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 676AC29B0668A939007173EB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 67F6FED5066B13B400443922 /* SDLMain.m in Sources */, 676AC29C0668A939007173EB /* 2dsline.c in Sources */, 676AC29D0668A939007173EB /* bitblt.c in Sources */, 676AC29E0668A939007173EB /* bitmap.c in Sources */, 676AC29F0668A939007173EB /* box.c in Sources */, 676AC2A00668A939007173EB /* canvas.c in Sources */, 676AC2A10668A939007173EB /* circle.c in Sources */, 676AC2A20668A939007173EB /* disc.c in Sources */, 676AC2A30668A939007173EB /* font.c in Sources */, 676AC2A40668A939007173EB /* gpixel.c in Sources */, 676AC2A60668A939007173EB /* line.c in Sources */, 676AC2A70668A939007173EB /* palette.c in Sources */, 676AC2A80668A939007173EB /* pcx.c in Sources */, 676AC2A90668A939007173EB /* pixel.c in Sources */, 676AC2AA0668A939007173EB /* poly.c in Sources */, 676AC2AB0668A939007173EB /* rect.c in Sources */, 676AC2AC0668A939007173EB /* rle.c in Sources */, 676AC2AD0668A939007173EB /* scalec.c in Sources */, 676AC2AF0668A939007173EB /* clipper.c in Sources */, 676AC2B00668A939007173EB /* draw.c in Sources */, 676AC2B10668A939007173EB /* globvars.c in Sources */, 676AC2B20668A939007173EB /* instance.c in Sources */, 676AC2B30668A939007173EB /* interp.c in Sources */, 676AC2B40668A939007173EB /* matrix.c in Sources */, 676AC2B50668A939007173EB /* points.c in Sources */, 676AC2B60668A939007173EB /* rod.c in Sources */, 676AC2B70668A939007173EB /* setup.c in Sources */, 676AC2C30668A939007173EB /* gr.c in Sources */, 676AC2C40668A939007173EB /* ogl.c in Sources */, 676AC2BA0668A939007173EB /* digi.c in Sources */, 676AC2BB0668A939007173EB /* event.c in Sources */, 676AC2BD0668A939007173EB /* joy.c in Sources */, 676AC2BF0668A939007173EB /* key.c in Sources */, 676AC2C00668A939007173EB /* mouse.c in Sources */, 676AC2C20668A939007173EB /* timer.c in Sources */, 676AC2C70668A939007173EB /* iff.c in Sources */, 676AC2CD0668A939007173EB /* ai.c in Sources */, 676AC2CF0668A939007173EB /* aipath.c in Sources */, 676AC2D00668A939007173EB /* automap.c in Sources */, 676AC2D10668A939007173EB /* bm.c in Sources */, 676AC2D30668A939007173EB /* cntrlcen.c in Sources */, 676AC2D40668A939007173EB /* collide.c in Sources */, 676AC2D50668A939007173EB /* config.c in Sources */, 676AC2D60668A939007173EB /* console.c in Sources */, 676AC2D70668A939007173EB /* controls.c in Sources */, 676AC2D80668A939007173EB /* credits.c in Sources */, 676AC2DA0668A939007173EB /* effects.c in Sources */, 676AC2DB0668A939007173EB /* endlevel.c in Sources */, 676AC2DD0668A939007173EB /* fireball.c in Sources */, 676AC2DE0668A939007173EB /* fuelcen.c in Sources */, 676AC2DF0668A939007173EB /* fvi.c in Sources */, 676AC2E00668A939007173EB /* game.c in Sources */, 676AC2E20668A939007173EB /* gamefont.c in Sources */, 676AC2E30668A939007173EB /* gamemine.c in Sources */, 676AC2E60668A939007173EB /* gamesave.c in Sources */, 676AC2E70668A939007173EB /* gameseg.c in Sources */, 676AC2E80668A939007173EB /* gameseq.c in Sources */, 676AC2E90668A939007173EB /* gauges.c in Sources */, 676AC2EA0668A939007173EB /* hostage.c in Sources */, 676AC2EB0668A939007173EB /* hud.c in Sources */, 676AC2EC0668A939007173EB /* inferno.c in Sources */, 676AC2ED0668A939007173EB /* kconfig.c in Sources */, 676032FA066B39CE008A67A3 /* kmatrix.c in Sources */, 676AC2EF0668A939007173EB /* laser.c in Sources */, 676AC2F00668A939007173EB /* lighting.c in Sources */, 676AC2F10668A939007173EB /* menu.c in Sources */, 676AC2F20668A939007173EB /* mglobal.c in Sources */, 676AC2F30668A939007173EB /* mission.c in Sources */, 676AC2F40668A939007173EB /* morph.c in Sources */, 676032E0066B399A008A67A3 /* multi.c in Sources */, 676032E1066B399A008A67A3 /* multibot.c in Sources */, EBAFC291088E67CD006329AD /* digiobj.c in Sources */, 676AC2F60668A939007173EB /* newdemo.c in Sources */, 676AC2F70668A939007173EB /* newmenu.c in Sources */, 676AC2F80668A939007173EB /* object.c in Sources */, 676AC2F90668A939007173EB /* paging.c in Sources */, 676AC2FA0668A939007173EB /* physics.c in Sources */, 676AC2FB0668A939007173EB /* piggy.c in Sources */, 676AC2FD0668A939007173EB /* playsave.c in Sources */, 676AC2FE0668A939007173EB /* polyobj.c in Sources */, 676AC2FF0668A939007173EB /* powerup.c in Sources */, 676AC3000668A939007173EB /* render.c in Sources */, 676AC3010668A939007173EB /* robot.c in Sources */, 676AC3020668A939007173EB /* scores.c in Sources */, 676AC3040668A939007173EB /* slew.c in Sources */, 676AC3050668A939007173EB /* songs.c in Sources */, 676AC3060668A939007173EB /* state.c in Sources */, 676AC3070668A939007173EB /* switch.c in Sources */, 676AC3080668A939007173EB /* terrain.c in Sources */, 676AC3090668A939007173EB /* texmerge.c in Sources */, 676AC30A0668A939007173EB /* text.c in Sources */, 676AC30B0668A939007173EB /* titles.c in Sources */, 676AC30C0668A939007173EB /* vclip.c in Sources */, 676AC30D0668A939007173EB /* wall.c in Sources */, 676AC30E0668A939007173EB /* weapon.c in Sources */, 676AC30F0668A939007173EB /* fixc.c in Sources */, 676AC3100668A939007173EB /* rand.c in Sources */, 676AC3110668A939007173EB /* tables.c in Sources */, 676AC3120668A939007173EB /* vecmat.c in Sources */, 676AC3130668A939007173EB /* mem.c in Sources */, 676AC3160668A939007173EB /* error.c in Sources */, 676AC3180668A939007173EB /* strio.c in Sources */, 676AC3190668A939007173EB /* strutil.c in Sources */, 676AC31A0668A939007173EB /* ntmap.c in Sources */, 676AC31B0668A939007173EB /* scanline.c in Sources */, EB92BE600CDD693C0045A32C /* digi_audio.c in Sources */, EB92BE610CDD693C0045A32C /* digi_mixer_music.c in Sources */, EB92BE620CDD693C0045A32C /* digi_mixer.c in Sources */, EB92BE630CDD693C0045A32C /* jukebox.c in Sources */, EB92BEA60CDD6A570045A32C /* dl_list.c in Sources */, EBEEB1EE0D2B317800FF39B4 /* custom.c in Sources */, EBAC98FB0D42497F0017D4BC /* ignorecase.c in Sources */, EBC58E710D489E19007C8ABF /* args.c in Sources */, EB3319850D50A6B200C799B0 /* bmread.c in Sources */, EB33198F0D50A70600C799B0 /* snddecom.c in Sources */, EBCE794E0DE59565008D8F82 /* rbaudio.c in Sources */, EB28D99C0ECEABD700E68E9B /* init.c in Sources */, EB35ABE20FB199B800C36930 /* window.c in Sources */, EBE8D7D10FD385E1009D181F /* gamecntl.c in Sources */, EBE8D8900FDA76D1009D181F /* gamerend.c in Sources */, EB8BE84F1071FBE00069486E /* player.c in Sources */, EB2EEB6910C5F8A3005256F2 /* net_udp.c in Sources */, 179E6E9F11F37B3400175C54 /* hmp.c in Sources */, EB1405BA12100883002B1CC6 /* physfsx.c in Sources */, EB0929FA12A10889004D9A79 /* messagebox.c in Sources */, EBAC9A171525C56300F6C779 /* inputbox.c in Sources */, EBAC9A181525C56D00F6C779 /* button.c in Sources */, EBAC9A191525C56D00F6C779 /* checkbox.c in Sources */, EBAC9A1A1525C56D00F6C779 /* dialog.c in Sources */, EBAC9A1B1525C56D00F6C779 /* file.c in Sources */, EBAC9A1C1525C56D00F6C779 /* gadget.c in Sources */, EBAC9A1D1525C56D00F6C779 /* icon.c in Sources */, EBAC9A1E1525C56D00F6C779 /* keypad.c in Sources */, EBAC9A1F1525C56D00F6C779 /* keypress.c in Sources */, EBAC9A201525C56D00F6C779 /* keytrap.c in Sources */, EBAC9A211525C56D00F6C779 /* listbox.c in Sources */, EBAC9A221525C56D00F6C779 /* menu.c in Sources */, EBAC9A231525C56D00F6C779 /* menubar.c in Sources */, EBAC9A241525C56D00F6C779 /* message.c in Sources */, EBAC9A251525C56D00F6C779 /* popup.c in Sources */, EBAC9A261525C56D00F6C779 /* radio.c in Sources */, EBAC9A271525C56D00F6C779 /* scroll.c in Sources */, EBAC9A281525C56D00F6C779 /* ui.c in Sources */, EBAC9A291525C56D00F6C779 /* uidraw.c in Sources */, EBAC9A2A1525C56D00F6C779 /* userbox.c in Sources */, EBAC9A3C1525C5E800F6C779 /* autosave.c in Sources */, EBAC9A4B1525C5E800F6C779 /* centers.c in Sources */, EBAC9A4C1525C5E800F6C779 /* curves.c in Sources */, EBAC9A4D1525C5E800F6C779 /* eglobal.c in Sources */, EBAC9A4E1525C5E800F6C779 /* ehostage.c in Sources */, EBAC9A4F1525C5E800F6C779 /* elight.c in Sources */, EBAC9A501525C5E800F6C779 /* eobject.c in Sources */, EBAC9A511525C5E800F6C779 /* eswitch.c in Sources */, EBAC9A521525C5E800F6C779 /* fixseg.c in Sources */, EBAC9A531525C5E800F6C779 /* func.c in Sources */, EBAC9A541525C5E800F6C779 /* group.c in Sources */, EBAC9A551525C5E800F6C779 /* info.c in Sources */, EBAC9A561525C5E800F6C779 /* kbuild.c in Sources */, EBAC9A571525C5E800F6C779 /* kcurve.c in Sources */, EBAC9A581525C5E800F6C779 /* kfuncs.c in Sources */, EBAC9A591525C5E800F6C779 /* kgame.c in Sources */, EBAC9A5B1525C5E800F6C779 /* khelp.c in Sources */, EBAC9A5C1525C5E800F6C779 /* kmine.c in Sources */, EBAC9A5D1525C5E800F6C779 /* ksegmove.c in Sources */, EBAC9A5E1525C5E800F6C779 /* ksegsel.c in Sources */, EBAC9A5F1525C5E800F6C779 /* ksegsize.c in Sources */, EBAC9A601525C5E800F6C779 /* ktmap.c in Sources */, EBAC9A611525C5E800F6C779 /* kview.c in Sources */, EBAC9A631525C5E800F6C779 /* med.c in Sources */, EBAC9A641525C5E800F6C779 /* meddraw.c in Sources */, EBAC9A651525C5E800F6C779 /* medmisc.c in Sources */, EBAC9A661525C5E800F6C779 /* medrobot.c in Sources */, EBAC9A671525C5E800F6C779 /* medsel.c in Sources */, EBAC9A681525C5E800F6C779 /* medwall.c in Sources */, EBAC9A691525C5E800F6C779 /* mine.c in Sources */, EBAC9A6A1525C5E800F6C779 /* objpage.c in Sources */, EBAC9A6B1525C5E800F6C779 /* segment.c in Sources */, EBAC9A6C1525C5E800F6C779 /* seguvs.c in Sources */, EBAC9A6D1525C5E800F6C779 /* texpage.c in Sources */, EBAC9A6E1525C5E800F6C779 /* texture.c in Sources */, EBAC9A6F1525C64400F6C779 /* dumpmine.c in Sources */, EBC4BAFB170E64550033D261 /* vers_id.c in Sources */, EBC4BB12170E660C0033D261 /* hash.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; EB775A6C105611320036C348 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( EB775A7A105611720036C348 /* extractD1Data.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ EB380D7B0E168B1900EBD9AD /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( EB380D7C0E168B1900EBD9AD /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ EB775A71105611330036C348 /* Development */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = d1Extract; ZERO_LINK = YES; }; name = Development; }; EB775A72105611330036C348 /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_MODEL_TUNING = G5; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = d1Extract; ZERO_LINK = NO; }; name = Deployment; }; EB775A73105611330036C348 /* Default */ = { isa = XCBuildConfiguration; buildSettings = { GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = d1Extract; ZERO_LINK = YES; }; name = Default; }; EBBAD4930B2D0F7E00080BBF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", ); FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( USE_SDLMIXER, EDITOR, ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; HEADER_SEARCH_PATHS = ( include, main, arch/sdl/include, ../physfs, "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, ); INFOPLIST_FILE = "d1x-Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../physfs/build/Debug\""; PRODUCT_NAME = d1x; WARNING_CFLAGS = "-Wall"; ZERO_LINK = NO; }; name = Development; }; EBBAD4940B2D0F7E00080BBF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", ); FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_PREPROCESSOR_DEFINITIONS = ( USE_SDLMIXER, EDITOR, NDEBUG, RELEASE, ); GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = ( include, main, arch/sdl/include, ../physfs, "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, ); INFOPLIST_FILE = "d1x-Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../physfs/build/Release\""; PRODUCT_NAME = d1x; SKIP_INSTALL = NO; WARNING_CFLAGS = "-Wall"; ZERO_LINK = NO; }; name = Deployment; }; EBBAD4950B2D0F7E00080BBF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_CONFIG_H, EDITOR, ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; HEADER_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, include, main, arch/sdl/include, ); INFOPLIST_FILE = "d1x-Info.plist"; INSTALL_PATH = "$(USER_APPS_DIR)"; LIBRARY_SEARCH_PATHS = ( "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", ); LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../../Library/Frameworks\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../physfs/build/Debug\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SRCROOT)/../physfs/build/Release\""; PRODUCT_NAME = d1x; WARNING_CFLAGS = "-Wall"; }; name = Default; }; EBBAD4970B2D0F7E00080BBF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", ); FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( USE_SDLMIXER, OGL, EDITOR, ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; HEADER_SEARCH_PATHS = ( include, main, arch/sdl/include, arch/ogl/include, ../physfs, "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, ); INFOPLIST_FILE = "d1xgl-Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../physfs/build/Debug\""; PRODUCT_NAME = d1xgl; WARNING_CFLAGS = "-Wall"; ZERO_LINK = NO; }; name = Development; }; EBBAD4980B2D0F7E00080BBF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", ); FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_PREPROCESSOR_DEFINITIONS = ( USE_SDLMIXER, OGL, EDITOR, NDEBUG, RELEASE, ); GCC_TREAT_WARNINGS_AS_ERRORS = NO; HEADER_SEARCH_PATHS = ( include, main, arch/sdl/include, arch/ogl/include, ../physfs, "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, ); INFOPLIST_FILE = "d1xgl-Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../physfs/build/Release\""; PRODUCT_NAME = d1xgl; SKIP_INSTALL = NO; WARNING_CFLAGS = "-Wall"; ZERO_LINK = NO; }; name = Deployment; }; EBBAD4990B2D0F7E00080BBF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Versions/A/Frameworks\""; GCC_PREPROCESSOR_DEFINITIONS = ( no_cpp_precomp, OGL, NDEBUG, ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; HEADER_SEARCH_PATHS = ( /Library/Frameworks/SDL.framework/Headers, include, main, arch/sdl/include, arch/ogl/include, "$(HOME)/Library/Frameworks/SDL.framework/Headers", ); INFOPLIST_FILE = "d1xgl-Info.plist"; INSTALL_PATH = "$(USER_APPS_DIR)"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(LIBRARY_SEARCH_PATHS_QUOTED_1)", "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2)", "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3)", "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4)", ); LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../../Library/Frameworks\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../physfs/build/Debug\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_2 = "\"$(SRCROOT)/../physfs/build/Release\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_3 = "\"$(SRCROOT)/../physfs/build/Release\""; LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_4 = "\"$(SRCROOT)/../physfs/build/Debug\""; PRODUCT_NAME = d1xgl; WARNING_CFLAGS = "-Wall"; }; name = Default; }; EBBAD49F0B2D0F7E00080BBF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PREFIX_HEADER = arch/carbon/conf.h; GCC_TREAT_WARNINGS_AS_ERRORS = YES; }; name = Development; }; EBBAD4A00B2D0F7E00080BBF /* Deployment */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); GCC_PREFIX_HEADER = arch/carbon/conf.h; GCC_VERSION_i386 = 4.0; GCC_VERSION_ppc = 3.3; MACOSX_DEPLOYMENT_TARGET = 10.1; MACOSX_DEPLOYMENT_TARGET_i386 = 10.4; MACOSX_DEPLOYMENT_TARGET_ppc = 10.1; OTHER_CFLAGS = "-lSystemStubs"; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Deployment; }; EBBAD4A10B2D0F7E00080BBF /* Default */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, ); SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = Default; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ EB775A76105611690036C348 /* Build configuration list for PBXNativeTarget "d1Extract" */ = { isa = XCConfigurationList; buildConfigurations = ( EB775A71105611330036C348 /* Development */, EB775A72105611330036C348 /* Deployment */, EB775A73105611330036C348 /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; EBBAD4920B2D0F7E00080BBF /* Build configuration list for PBXNativeTarget "d1x" */ = { isa = XCConfigurationList; buildConfigurations = ( EBBAD4930B2D0F7E00080BBF /* Development */, EBBAD4940B2D0F7E00080BBF /* Deployment */, EBBAD4950B2D0F7E00080BBF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; EBBAD4960B2D0F7E00080BBF /* Build configuration list for PBXNativeTarget "d1xgl" */ = { isa = XCConfigurationList; buildConfigurations = ( EBBAD4970B2D0F7E00080BBF /* Development */, EBBAD4980B2D0F7E00080BBF /* Deployment */, EBBAD4990B2D0F7E00080BBF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; EBBAD49E0B2D0F7E00080BBF /* Build configuration list for PBXProject "d1x-rebirth" */ = { isa = XCConfigurationList; buildConfigurations = ( EBBAD49F0B2D0F7E00080BBF /* Development */, EBBAD4A00B2D0F7E00080BBF /* Deployment */, EBBAD4A10B2D0F7E00080BBF /* Default */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Default; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } dxx-rebirth-0.58.1-d1x/d1x-rebirth.xpm000066400000000000000000004752041217717257200174450ustar00rootroot00000000000000/* XPM */ static char *pixmap[] = { "128 128 8069 2", " c None", ". c #7E604C", "+ c #7F614C", "@ c #785D4C", "# c #69423F", "$ c #7D392A", "% c #773E2B", "& c #732E2F", "* c #7B342D", "= c #68272D", "- c #491430", "; c #531731", "> c #652230", ", c #6A2531", "' c #7A332E", ") c #83422C", "! c #7C3B2D", "~ c #702E2F", "{ c #712F2E", "] c #78392B", "^ c #81412A", "/ c #813D2B", "( c #7D322F", "_ c #7D362F", ": c #80462C", "< c #80472E", "[ c #804F2D", "} c #804F2C", "| c #803F30", "1 c #80412F", "2 c #804A2D", "3 c #804D2B", "4 c #804E2A", "5 c #804B2B", "6 c #80402E", "7 c #803B30", "8 c #7C3532", "9 c #7A3532", "0 c #7F422E", "a c #81452B", "b c #80412B", "c c #7F3C2C", "d c #7E3B2C", "e c #804629", "f c #80452C", "g c #80432D", "h c #80492C", "i c #804A2C", "j c #804F2B", "k c #80512B", "l c #80472D", "m c #80452D", "n c #80462D", "o c #805428", "p c #805629", "q c #80502A", "r c #80482D", "s c #80522C", "t c #80592E", "u c #80572C", "v c #815828", "w c #815729", "x c #805828", "y c #80624D", "z c #81634D", "A c #7B5F4D", "B c #6A4D3D", "C c #7E4B27", "D c #814529", "E c #782E2F", "F c #6F2A2F", "G c #702F2D", "H c #632430", "I c #6E2B30", "J c #803B2D", "K c #7E3030", "L c #7E3130", "M c #7D372C", "N c #78352B", "O c #752F2E", "P c #7A302E", "Q c #79322C", "R c #742F2E", "S c #6E2731", "T c #742932", "U c #7D432D", "V c #7F5729", "W c #7E4E2C", "X c #7E4A2E", "Y c #7E482E", "Z c #7E4630", "` c #7E4A2F", " . c #7E492C", ".. c #7E452D", "+. c #7E462D", "@. c #7D3E2D", "#. c #7D3630", "$. c #7E3A30", "%. c #7F402E", "&. c #7E412D", "*. c #7E392F", "=. c #804B2A", "-. c #7D4B29", ";. c #773030", ">. c #7A3031", ",. c #7E3C2F", "'. c #7E3E2E", "). c #7E452C", "!. c #7E4F29", "~. c #7E5128", "{. c #7E442D", "]. c #7E472D", "^. c #7E4F28", "/. c #7E522A", "(. c #7E512B", "_. c #7E5429", ":. c #7E542A", "<. c #7E552A", "[. c #7E5A28", "}. c #805B29", "|. c #81572A", "1. c #815629", "2. c #7F5628", "3. c #795C49", "4. c #684E3F", "5. c #674E3E", "6. c #674F3E", "7. c #624C3E", "8. c #654634", "9. c #9A5329", "0. c #994E2D", "a. c #96452C", "b. c #90442C", "c. c #96422B", "d. c #9C4A2C", "e. c #9A562C", "f. c #965529", "g. c #94412C", "h. c #923C2D", "i. c #8F3A2B", "j. c #8C382C", "k. c #95462A", "l. c #9B4E27", "m. c #8B3E2B", "n. c #7D2F2E", "o. c #802E31", "p. c #8C3F2F", "q. c #985629", "r. c #986725", "s. c #97642A", "t. c #97572C", "u. c #97582C", "v. c #976A2A", "w. c #976429", "x. c #975E2B", "y. c #975D2B", "z. c #97602B", "A. c #975A2B", "B. c #964F2C", "C. c #964C2B", "D. c #97512A", "E. c #97582B", "F. c #97562C", "G. c #986427", "H. c #975F25", "I. c #974C2C", "J. c #974B2E", "K. c #97512B", "L. c #97542A", "M. c #975A26", "N. c #975C26", "O. c #975A2C", "P. c #97592D", "Q. c #975E2A", "R. c #975C29", "S. c #975D2A", "T. c #976327", "U. c #976629", "V. c #976329", "W. c #97622A", "X. c #98642C", "Y. c #986629", "Z. c #8A5E29", "`. c #7C502C", " + c #7F4E2B", ".+ c #654E3E", "++ c #000000", "@+ c #070301", "#+ c #784A0F", "$+ c #FFB726", "%+ c #FCA121", "&+ c #FB981F", "*+ c #FE9920", "=+ c #FA8F1C", "-+ c #FDA21E", ";+ c #FFAE22", ">+ c #FF9B1D", ",+ c #FF961B", "'+ c #FF9A1E", ")+ c #FB921E", "!+ c #FF971D", "~+ c #FF9D1E", "{+ c #F7931F", "]+ c #F68E1D", "^+ c #FC971E", "/+ c #FFA21E", "(+ c #FE9B19", "_+ c #FEA31B", ":+ c #FFB622", "<+ c #FFB121", "[+ c #FFAE1E", "}+ c #FFB420", "|+ c #FFB521", "1+ c #FFB01F", "2+ c #FFB120", "3+ c #FFB422", "4+ c #FFB222", "5+ c #FFA820", "6+ c #FFA01D", "7+ c #FFA91F", "8+ c #FFAD22", "9+ c #FFB021", "0+ c #FFAF20", "a+ c #FEA01D", "b+ c #FB901A", "c+ c #FE9E1E", "d+ c #FFAF21", "e+ c #FEA21F", "f+ c #FE921B", "g+ c #FF931B", "h+ c #FFA920", "i+ c #FFB623", "j+ c #FFAC1F", "k+ c #FFAE20", "l+ c #FFAD1E", "m+ c #FFB321", "n+ c #FFAB1F", "o+ c #FFB820", "p+ c #FCB221", "q+ c #B07726", "r+ c #72442C", "s+ c #7F4A2B", "t+ c #7E4829", "u+ c #080501", "v+ c #7A500E", "w+ c #FEBB24", "x+ c #F58D1B", "y+ c #EC7F17", "z+ c #FF981D", "A+ c #FFA71F", "B+ c #FFB122", "C+ c #FFAD21", "D+ c #FF9B1B", "E+ c #FF941A", "F+ c #FFA11D", "G+ c #FFA720", "H+ c #FFA11C", "I+ c #FFA61D", "J+ c #FFA41D", "K+ c #FFA51C", "L+ c #FFA91E", "M+ c #FF981A", "N+ c #FF9A19", "O+ c #FFB21E", "P+ c #FFBF23", "Q+ c #FFC124", "R+ c #FFB51F", "S+ c #FFA31A", "T+ c #FFA31B", "U+ c #FFA81D", "V+ c #FFAC1D", "W+ c #FFAB20", "X+ c #FF9B1E", "Y+ c #FF951B", "Z+ c #FFA31E", "`+ c #FF971B", " @ c #FFA11F", ".@ c #FFAE21", "+@ c #FFB725", "@@ c #FFAA20", "#@ c #FFA01C", "$@ c #FFB824", "%@ c #FFB520", "&@ c #FFB522", "*@ c #FFB922", "=@ c #FFB621", "-@ c #FFB11D", ";@ c #FFB721", ">@ c #FFBC22", ",@ c #F9B922", "'@ c #B2762A", ")@ c #72302F", "!@ c #7D382C", "~@ c #7C392B", "{@ c #070501", "]@ c #794C0E", "^@ c #FEAA1D", "/@ c #FC8A1A", "(@ c #F98F1C", "_@ c #FEA01F", ":@ c #FFB123", "<@ c #FEAF23", "[@ c #FE9F1E", "}@ c #FE941B", "|@ c #FDA020", "1@ c #FEA521", "2@ c #FEA11E", "3@ c #FEAB20", "4@ c #FEB421", "5@ c #FEAD1C", "6@ c #FEB21E", "7@ c #FEB622", "8@ c #FDA31D", "9@ c #FD9F1B", "0@ c #FEB01F", "a@ c #FEB821", "b@ c #FEB921", "c@ c #FEB620", "d@ c #FEA81C", "e@ c #FE991A", "f@ c #FE9C1C", "g@ c #FEAA20", "h@ c #FEAF21", "i@ c #FEA620", "j@ c #FEA220", "k@ c #FEAA22", "l@ c #FEB224", "m@ c #FEA622", "n@ c #FD981C", "o@ c #FCA01F", "p@ c #FEB124", "q@ c #FEB023", "r@ c #FEA61F", "s@ c #FEB825", "t@ c #FEBD26", "u@ c #FEAC1F", "v@ c #FEAE22", "w@ c #FEB523", "x@ c #FEB623", "y@ c #FEB221", "z@ c #FEB021", "A@ c #FEB422", "B@ c #FEB320", "C@ c #FEB121", "D@ c #FEAF1F", "E@ c #FFB61F", "F@ c #F9B421", "G@ c #B17129", "H@ c #6D2531", "I@ c #76282F", "J@ c #762C2D", "K@ c #7D4E0C", "L@ c #FEAF1D", "M@ c #FE9C1D", "N@ c #FFA21F", "O@ c #FFA41F", "P@ c #FEAC22", "Q@ c #FEAC21", "R@ c #FC9D1E", "S@ c #FD961C", "T@ c #FC941B", "U@ c #F68C1B", "V@ c #FA961D", "W@ c #FF9F1E", "X@ c #FE9E1B", "Y@ c #FEA91D", "Z@ c #FEB420", "`@ c #FEB51D", " # c #FEAE1C", ".# c #FEA81D", "+# c #FE9F1B", "@# c #FEA41A", "## c #FEB520", "$# c #FEBA21", "%# c #FEA61E", "&# c #FEA31E", "*# c #FEA920", "=# c #FEA821", "-# c #FEA11F", ";# c #FEA31F", "># c #FEA51F", ",# c #FEAA21", "'# c #FEA921", ")# c #FEAC23", "!# c #FEB123", "~# c #FEB222", "{# c #FEB122", "]# c #FEB524", "^# c #FEB925", "/# c #FEBE27", "(# c #FEBF27", "_# c #FEB824", ":# c #FEB21F", "<# c #FEAF1E", "[# c #FFB21C", "}# c #FAAF1E", "|# c #B16928", "1# c #682331", "2# c #732E2D", "3# c #76332B", "4# c #0B0601", "5# c #845C0F", "6# c #FECA24", "7# c #FDAC20", "8# c #FEA71F", "9# c #FE9E1D", "0# c #F78F1A", "a# c #F68B1A", "b# c #FA921D", "c# c #ED831B", "d# c #F1871C", "e# c #FC991E", "f# c #FE9A1A", "g# c #FFA61C", "h# c #FEB220", "i# c #FEB720", "j# c #FEB022", "k# c #FEB223", "l# c #FEAB1F", "m# c #FEB71E", "n# c #FEB31D", "o# c #FEB11F", "p# c #FEA41E", "q# c #FE9F1D", "r# c #FEA020", "s# c #FE991D", "t# c #FEA01E", "u# c #FEAD22", "v# c #FEA91F", "w# c #FEA720", "x# c #FEAC20", "y# c #FEB323", "z# c #FEBB25", "A# c #FEBC23", "B# c #FFBC25", "C# c #FFC428", "D# c #FFC327", "E# c #FFBF25", "F# c #FFB620", "G# c #FEAB1D", "H# c #FEB120", "I# c #FEB723", "J# c #FEB020", "K# c #FEA61D", "L# c #FEAA1F", "M# c #FFB31F", "N# c #F8A71F", "O# c #AC5D2B", "P# c #5D1D31", "Q# c #692C2C", "R# c #6E302A", "S# c #0C0601", "T# c #876211", "U# c #FED026", "V# c #FFB022", "W# c #FE9D1D", "X# c #F9971B", "Y# c #F78B19", "Z# c #F68D1D", "`# c #E9831E", " $ c #E27E1A", ".$ c #EB8419", "+$ c #F9961B", "@$ c #FFA71D", "#$ c #FEAC1E", "$$ c #FEBA27", "%$ c #FEB726", "&$ c #FEA91E", "*$ c #FEA81B", "=$ c #FEB81F", "-$ c #FEC022", ";$ c #FEAE20", ">$ c #FEAD21", ",$ c #FEA11D", "'$ c #FE9C1B", ")$ c #FEB621", "!$ c #FEAF20", "~$ c #FFB926", "{$ c #FFBF28", "]$ c #FFBE24", "^$ c #FFC727", "/$ c #FFBD20", "($ c #FFB91F", "_$ c #FEBF25", ":$ c #FEB521", "<$ c #FEA61C", "[$ c #FEA41C", "}$ c #FEAB21", "|$ c #EF8A1C", "1$ c #924128", "2$ c #4A1332", "3$ c #5C232D", "4$ c #5F252A", "5$ c #0E0701", "6$ c #885F10", "7$ c #FEC423", "8$ c #FDA11C", "9$ c #FCA51F", "0$ c #FE9E1C", "a$ c #FF9A1D", "b$ c #FF931D", "c$ c #F3891D", "d$ c #DC781A", "e$ c #D37217", "f$ c #E27E16", "g$ c #F4921A", "h$ c #F8981F", "i$ c #F8961E", "j$ c #FD961A", "k$ c #FFA81F", "l$ c #FFBC26", "m$ c #FFB023", "n$ c #FEBA25", "o$ c #FEC124", "p$ c #FFBF22", "q$ c #FFBE22", "r$ c #FEAE1F", "s$ c #FEBD25", "t$ c #FEB423", "u$ c #FEA41F", "v$ c #FFB823", "w$ c #FFBA24", "x$ c #FFBD25", "y$ c #FFBC23", "z$ c #FFC525", "A$ c #FFCC26", "B$ c #FEC420", "C$ c #FFC623", "D$ c #FFCB27", "E$ c #FFC628", "F$ c #FFC125", "G$ c #FEB41F", "H$ c #FEAB23", "I$ c #FE8F1A", "J$ c #E4761A", "K$ c #813728", "L$ c #400F33", "M$ c #511D2D", "N$ c #501D2C", "O$ c #090601", "P$ c #7C540F", "Q$ c #FB9118", "R$ c #FB9F1D", "S$ c #FEAC1C", "T$ c #FD9B18", "U$ c #FD921B", "V$ c #FC921E", "W$ c #F68E1E", "X$ c #ED881D", "Y$ c #EA841B", "Z$ c #EC881A", "`$ c #E3871C", " % c #D07B1C", ".% c #CF741A", "+% c #E97C17", "@% c #FD981B", "#% c #F9A31E", "$% c #F38F19", "%% c #FB981E", "&% c #FFBB27", "*% c #FFC425", "=% c #FFBE20", "-% c #FFC324", ";% c #FEC426", ">% c #FEB920", ",% c #FEAD1A", "'% c #FFB225", ")% c #FF9F1F", "!% c #FD9A1E", "~% c #FDA420", "{% c #FFBA22", "]% c #FFBD24", "^% c #FFC025", "/% c #FFC926", "(% c #FFD028", "_% c #FFD226", ":% c #FFD027", "<% c #FFC523", "[% c #FFC423", "}% c #FFCA29", "|% c #FFC426", "1% c #FEBF23", "2% c #FEBD23", "3% c #FD981D", "4% c #964A2A", "5% c #4C1831", "6% c #4C1D2F", "7% c #43172E", "8% c #060400", "9% c #704B0E", "0% c #FFB921", "a% c #FEA71D", "b% c #FFAF1C", "c% c #FF9C1A", "d% c #FD8E1B", "e% c #F38A1B", "f% c #F18718", "g% c #FD991D", "h% c #FEA121", "i% c #EA891B", "j% c #D47619", "k% c #BF711D", "l% c #A86318", "m% c #C16715", "n% c #DE7717", "o% c #D97816", "p% c #D16E14", "q% c #E37B18", "r% c #F59F1F", "s% c #FDB820", "t% c #FFC322", "u% c #FEC926", "v% c #FFC725", "w% c #FFBB1F", "x% c #FEBE20", "y% c #FEC123", "z% c #FFB41D", "A% c #FEA517", "B% c #FEB01E", "C% c #E8871C", "D% c #D06E14", "E% c #E08618", "F% c #FAAC20", "G% c #FFBD23", "H% c #FFC024", "I% c #FFC126", "J% c #FFC325", "K% c #FFC826", "L% c #FFCF26", "M% c #FFD224", "N% c #FFCF23", "O% c #FEC722", "P% c #FFCB25", "Q% c #FFCD2B", "R% c #FFC629", "S% c #FFC226", "T% c #FFBC20", "U% c #FEB01C", "V% c #F78B1F", "W% c #A65425", "X% c #652A2C", "Y% c #56232D", "Z% c #47192E", "`% c #000001", " & c #000102", ".& c #000203", "+& c #000204", "@& c #000406", "#& c #000408", "$& c #000409", "%& c #00030C", "&& c #05070C", "*& c #68501C", "=& c #FAC333", "-& c #F3C131", ";& c #F0B92B", ">& c #F3B024", ",& c #F4AC24", "'& c #F89D22", ")& c #F5901F", "!& c #EA821A", "~& c #ED8016", "{& c #FC9B1D", "]& c #FFA921", "^& c #FB951C", "/& c #F4881B", "(& c #E5871E", "_& c #BF741B", ":& c #B26517", "<& c #B76016", "[& c #BD6618", "}& c #CC7A1B", "|& c #CE771A", "1& c #D07316", "2& c #E88C1B", "3& c #F7A921", "4& c #FEBB23", "5& c #FFC122", "6& c #FEBB1F", "7& c #FEBB20", "8& c #FFBD21", "9& c #FFBB22", "0& c #FFB61D", "a& c #F6A321", "b& c #A86218", "c& c #76360D", "d& c #BA6A14", "e& c #F9B11F", "f& c #FFCA28", "g& c #FFCE28", "h& c #FFCD26", "i& c #FFD628", "j& c #FFD82A", "k& c #FFD528", "l& c #FFD225", "m& c #FFCC24", "n& c #FFC724", "o& c #FFC121", "p& c #FEB820", "q& c #F99520", "r& c #B05F25", "s& c #6D312C", "t& c #62292E", "u& c #5A242B", "v& c #000202", "w& c #000304", "x& c #000508", "y& c #00070E", "z& c #000913", "A& c #000A1A", "B& c #000C21", "C& c #000F27", "D& c #00102D", "E& c #001333", "F& c #001335", "G& c #031838", "H& c #4A4F44", "I& c #C2A156", "J& c #B4A655", "K& c #B79D4D", "L& c #BF9A47", "M& c #C79C45", "N& c #CE9741", "O& c #D49439", "P& c #DC9433", "Q& c #E89C2D", "R& c #F0A42A", "S& c #F6A425", "T& c #FC9D21", "U& c #F8901D", "V& c #E97F18", "W& c #D17418", "X& c #BF6B16", "Y& c #C86E18", "Z& c #DD7B1B", "`& c #F49D25", " * c #ECA024", ".* c #D67D19", "+* c #CE6714", "@* c #D76C14", "#* c #F28D19", "$* c #FEC024", "%* c #FFB821", "&* c #FFB720", "** c #FFB825", "=* c #FFB61E", "-* c #F3A421", ";* c #AD6819", ">* c #985214", ",* c #D9881A", "'* c #FFC223", ")* c #FFBB21", "!* c #FFC928", "~* c #FFCC27", "{* c #FFCA24", "]* c #FFD52B", "^* c #FFDE30", "/* c #FFDB2D", "(* c #FFCD21", "_* c #FFCB23", ":* c #FFC622", "<* c #FFBC24", "[* c #F9A221", "}* c #B16127", "|* c #78372A", "1* c #743628", "2* c #000101", "3* c #000206", "4* c #00060C", "5* c #000B16", "6* c #001121", "7* c #00162C", "8* c #001B3A", "9* c #012248", "0* c #022856", "a* c #032E63", "b* c #093971", "c* c #1A447C", "d* c #104A84", "e* c #104C89", "f* c #104C8D", "g* c #2A6092", "h* c #5B8B9B", "i* c #538A9A", "j* c #5A7D91", "k* c #647F8A", "l* c #6F8A87", "m* c #798E80", "n* c #888B74", "o* c #99906A", "p* c #A89E60", "q* c #B89D51", "r* c #CAA045", "s* c #DCA93D", "t* c #E29B30", "u* c #DA7F20", "v* c #D4761A", "w* c #DD7E19", "x* c #F3911C", "y* c #FE931C", "z* c #FF981E", "A* c #FFB224", "B* c #E47F19", "C* c #D76B14", "D* c #EB7112", "E* c #FE8F18", "F* c #FFB624", "G* c #FFBB25", "H* c #FEB71F", "I* c #FFAC1C", "J* c #F6A221", "K* c #FBA221", "L* c #FEBD21", "M* c #FFC224", "N* c #FFD328", "O* c #FFD82C", "P* c #FFD129", "Q* c #FFCB26", "R* c #FFB822", "S* c #F9A821", "T* c #B06127", "U* c #6F2C2E", "V* c #7F3C29", "W* c #7D3F27", "X* c #000205", "Y* c #00050C", "Z* c #001225", "`* c #001A38", " = c #00254D", ".= c #003261", "+= c #024078", "@= c #085293", "#= c #146EA9", "$= c #1E85BB", "%= c #4897C8", "&= c #72AAD4", "*= c #6BBBDD", "== c #3BC0E3", "-= c #43C2E8", ";= c #3AA6E9", ">= c #3EA4E8", ",= c #60C6ED", "'= c #56BAEB", ")= c #2996E1", "!= c #1A7ECF", "~= c #2377B7", "{= c #2A7CB0", "]= c #3179AC", "^= c #3D79A2", "/= c #487D99", "(= c #5D828E", "_= c #758C82", ":= c #8D9372", "<= c #A8975F", "[= c #BF9B4D", "}= c #D29539", "|= c #E8932D", "1= c #F69927", "2= c #FC9820", "3= c #FC961A", "4= c #FDAC1F", "5= c #FFB21F", "6= c #FFA21D", "7= c #FBA421", "8= c #F99A1C", "9= c #FC8E17", "0= c #FEA51D", "a= c #FEB522", "b= c #FFB923", "c= c #FEBB21", "d= c #FFC022", "e= c #FFC624", "f= c #FFC81F", "g= c #FFCC22", "h= c #FFCE26", "i= c #FE9D1E", "j= c #FEB922", "k= c #F9AB22", "l= c #B06E27", "m= c #70382B", "n= c #7D3D29", "o= c #7C3C28", "p= c #000307", "q= c #000910", "r= c #001020", "s= c #001A35", "t= c #00366A", "u= c #044B87", "v= c #07569B", "w= c #0B62AD", "x= c #1584C9", "y= c #249DE1", "z= c #37B9F2", "A= c #40D6FF", "B= c #ACFFFF", "C= c #FDFFFF", "D= c #96FFFF", "E= c #49FDFF", "F= c #5FFFFF", "G= c #60E9FF", "H= c #7DE9FF", "I= c #D7FFFF", "J= c #D8FEFF", "K= c #80DFFF", "L= c #29A9EF", "M= c #1177C2", "N= c #1969AB", "O= c #1A6EAD", "P= c #176BAB", "Q= c #1562A5", "R= c #1B6BAC", "S= c #2675B1", "T= c #326EA3", "U= c #467799", "V= c #68908F", "W= c #8A9378", "X= c #A98C5E", "Y= c #C48E48", "Z= c #DA8D34", "`= c #EC9D28", " - c #F8B224", ".- c #FDB21F", "+- c #FFA81B", "@- c #FFAF1E", "#- c #FEAD1B", "$- c #FEB31F", "%- c #FFB724", "&- c #FEB721", "*- c #FEBD22", "=- c #FFB81C", "-- c #FFC524", ";- c #FFC922", ">- c #FFCF25", ",- c #FFCC25", "'- c #FFCD2A", ")- c #FE991B", "!- c #FE911A", "~- c #FEAB1E", "{- c #F9AE22", "]- c #B07527", "^- c #713C28", "/- c #7F3E29", "(- c #7D3C27", "_- c #000201", ":- c #000912", "<- c #001023", "[- c #001D3D", "}- c #002E5E", "|- c #02427F", "1- c #06569F", "2- c #0D70B8", "3- c #1583C6", "4- c #197FC5", "5- c #2083C8", "6- c #2A9CD4", "7- c #2FA0D8", "8- c #33A3DC", "9- c #31AFE7", "0- c #63DAF5", "a- c #C4F7FF", "b- c #AEFFFF", "c- c #7AF7FF", "d- c #95FFFF", "e- c #B2FFFF", "f- c #CAFFFF", "g- c #DEFEFF", "h- c #DDFEFF", "i- c #DEFFFF", "j- c #95EAFD", "k- c #2AA7E3", "l- c #1970B4", "m- c #256CA1", "n- c #246FA3", "o- c #1E659A", "p- c #1B639C", "q- c #1A6AA7", "r- c #1663A4", "s- c #1462A4", "t- c #1D6BAA", "u- c #2C72AA", "v- c #46799D", "w- c #667D85", "x- c #8A7B69", "y- c #B58A4D", "z- c #D9A538", "A- c #ECAE2A", "B- c #FDA51B", "C- c #FFBA21", "D- c #FEAC1B", "E- c #FEAC1A", "F- c #FEB31E", "G- c #FFB924", "H- c #FEBC22", "I- c #FFBD22", "J- c #FFBE21", "K- c #FFCF28", "L- c #FFC626", "M- c #FFBE25", "N- c #FFB723", "O- c #FEB822", "P- c #F9B625", "Q- c #B06E26", "R- c #72342A", "S- c #7D3929", "T- c #7B3928", "U- c #000911", "V- c #001223", "W- c #001E3F", "X- c #013665", "Y- c #044F8D", "Z- c #0963AD", "`- c #1072C1", " ; c #1B8DD1", ".; c #2397D3", "+; c #238CC9", "@; c #2383C1", "#; c #2687C0", "$; c #2789C0", "%; c #2484BC", "&; c #2587C0", "*; c #2688C5", "=; c #1A95D3", "-; c #43C5F0", ";; c #BCF2FE", ">; c #EBFFFF", ",; c #DFFDFF", "'; c #CAF5FE", "); c #AAEDFD", "!; c #5DDEFD", "~; c #5CE4FF", "{; c #A0FAFF", "]; c #ECFFFF", "^; c #9EE8FF", "/; c #40AEE2", "(; c #2986C2", "_; c #2C7EB4", ":; c #2D74A4", "<; c #2A719F", "[; c #2A70A1", "}; c #236595", "|; c #1E5F91", "1; c #195E95", "2; c #1561A0", "3; c #1565A7", "4; c #1A66A8", "5; c #3270A3", "6; c #5F8391", "7; c #909371", "8; c #B99E4F", "9; c #D9A838", "0; c #EEA82A", "a; c #FAAE24", "b; c #FFB423", "c; c #FFB020", "d; c #FEB11D", "e; c #FEAF1B", "f; c #FFBA28", "g; c #FEB928", "h; c #FEB722", "i; c #FEBA20", "j; c #FFC424", "k; c #FFC222", "l; c #FFC123", "m; c #FFC625", "n; c #FFCA26", "o; c #FFC824", "p; c #FFCA27", "q; c #FFC726", "r; c #F9B224", "s; c #B06427", "t; c #712F2B", "u; c #7C392A", "v; c #7A3829", "w; c #00070D", "x; c #000F1F", "y; c #001C3C", "z; c #003264", "A; c #045091", "B; c #0D75BA", "C; c #1588D0", "D; c #1C8BD2", "E; c #2087CE", "F; c #2695CF", "G; c #2793CB", "H; c #2285C4", "I; c #248AC7", "J; c #248BC5", "K; c #2487C2", "L; c #2486BF", "M; c #2587BF", "N; c #2887BE", "O; c #2688C1", "P; c #1F93D0", "Q; c #57C7F0", "R; c #C1F8FE", "S; c #8EDEFA", "T; c #43B8EB", "U; c #3EB8E9", "V; c #29A9E8", "W; c #30B9F4", "X; c #55DEFC", "Y; c #BCFBFF", "Z; c #EDFFFF", "`; c #A7F7FF", " > c #4EC2ED", ".> c #2385C3", "+> c #2975AA", "@> c #3381AD", "#> c #2F7CA9", "$> c #276998", "%> c #266694", "&> c #276997", "*> c #256796", "=> c #1F6294", "-> c #186099", ";> c #1567A6", ">> c #1F76B3", ",> c #387EAC", "'> c #5F8992", ")> c #919B71", "!> c #C09E4C", "~> c #DFA133", "{> c #F3A828", "]> c #FFAC1E", "^> c #FEAC1D", "/> c #FFAC22", "(> c #FFB627", "_> c #FEB026", ":> c #FEAB24", "<> c #FEB025", "[> c #FEB324", "}> c #FEB321", "|> c #FEB41E", "1> c #FFC023", "2> c #FFBB20", "3> c #FFC323", "4> c #FFB920", "5> c #FAA521", "6> c #B26226", "7> c #70312C", "8> c #7D382B", "9> c #7B382A", "0> c #000509", "a> c #000B17", "b> c #001630", "c> c #002A57", "d> c #024586", "e> c #0965B3", "f> c #1585D1", "g> c #2095DB", "h> c #2495D7", "i> c #2491D2", "j> c #2490CE", "k> c #238DCD", "l> c #238ECC", "m> c #2696CF", "n> c #299BD2", "o> c #2691CB", "p> c #258CC7", "q> c #268CC6", "r> c #288DC6", "s> c #298FC5", "t> c #2A8DC2", "u> c #288BBF", "v> c #28A1D7", "w> c #44CCF3", "x> c #30A7E1", "y> c #1C88C6", "z> c #2C96CC", "A> c #3596CB", "B> c #3898D2", "C> c #41B4EA", "D> c #5ADDFF", "E> c #81EAFF", "F> c #ADFAFF", "G> c #AEF3FE", "H> c #4FACE1", "I> c #1B7AB7", "J> c #2D77A7", "K> c #2E76A5", "L> c #286E9F", "M> c #2B72A0", "N> c #2D7BA9", "O> c #2A73A3", "P> c #286B9B", "Q> c #216496", "R> c #1C659C", "S> c #1767A5", "T> c #1D6FAD", "U> c #377CA4", "V> c #698B89", "W> c #9A8C62", "X> c #B7853D", "Y> c #D58927", "Z> c #F39B21", "`> c #FEA421", " , c #FEAC25", "., c #FEB227", "+, c #FEA924", "@, c #FEA923", "#, c #FEB61F", "$, c #FFC326", "%, c #FFBC21", "&, c #FFBA20", "*, c #FFA81C", "=, c #F3901D", "-, c #AC5D25", ";, c #72352D", ">, c #7D3B2C", ",, c #7B3D2B", "', c #00080E", "), c #001022", "!, c #002146", "~, c #013F77", "{, c #075FAA", "], c #127BCC", "^, c #1E8FDB", "/, c #2494DB", "(, c #2494D7", "_, c #2498D5", ":, c #26A0D9", "<, c #28A2DA", "[, c #2597D4", "}, c #2697D4", "|, c #2DAADA", "1, c #2CA5D8", "2, c #2796CF", "3, c #2691CC", "4, c #2891C9", "5, c #2A93CB", "6, c #2B95CB", "7, c #2A8FC5", "8, c #2C91C4", "9, c #339FD1", "0, c #2DA5E0", "a, c #2991C8", "b, c #2E8BBD", "c, c #3291C3", "d, c #328FBF", "e, c #3289BC", "f, c #379AD5", "g, c #3DBEFA", "h, c #37D0FF", "i, c #6AE0FF", "j, c #BDEDFE", "k, c #39ABE2", "l, c #2174B0", "m, c #2B6B9C", "n, c #2B6F9E", "o, c #2B73A2", "p, c #2C77A5", "q, c #2A71A0", "r, c #276D9D", "s, c #276C9A", "t, c #296D9E", "u, c #276B9C", "v, c #226393", "w, c #1B5F96", "x, c #1463A3", "y, c #2170AB", "z, c #3E749E", "A, c #586876", "B, c #83674C", "C, c #C78532", "D, c #F4AB2C", "E, c #FDB629", "F, c #FFAB25", "G, c #FFAA25", "H, c #FFAC26", "I, c #FEB322", "J, c #FEB51F", "K, c #FFBE23", "L, c #FC9B1A", "M, c #E27818", "N, c #A04F25", "O, c #75382D", "P, c #80462A", "Q, c #7D4629", "R, c #000407", "S, c #000B14", "T, c #00162E", "U, c #002B59", "V, c #035093", "W, c #0F7DC6", "X, c #1B90DD", "Y, c #2295DF", "Z, c #269DDE", "`, c #259CDC", " ' c #249EDB", ".' c #27A4DD", "+' c #29A7E0", "@' c #29A5DE", "#' c #279DDA", "$' c #289CD8", "%' c #2BA4D9", "&' c #2BA2D9", "*' c #299CD4", "=' c #2A9CD3", "-' c #2B9CD1", ";' c #2A98CF", ">' c #2B95CC", ",' c #2C93C9", "'' c #2E96CA", ")' c #33A1D0", "!' c #359FD0", "~' c #3093C3", "{' c #3092C3", "]' c #3091C3", "^' c #318DC1", "/' c #338FC4", "(' c #3796CC", "_' c #3EA7E1", ":' c #43B9F4", "<' c #4BCBFD", "[' c #95EEFF", "}' c #8CE1FB", "|' c #2C95CF", "1' c #286FA4", "2' c #2E709F", "3' c #2B6FA0", "4' c #296C9C", "5' c #296C9B", "6' c #296B99", "7' c #296E9F", "8' c #2B74A8", "9' c #2971A2", "0' c #276796", "a' c #216495", "b' c #19639D", "c' c #1465A8", "d' c #1E6AAA", "e' c #446F90", "f' c #8F7D62", "g' c #D29942", "h' c #F0B033", "i' c #FAB22B", "j' c #FCA323", "k' c #FB9C21", "l' c #FEA825", "m' c #FFB126", "n' c #FEAD1F", "o' c #FE9E1A", "p' c #FEA81E", "q' c #FFB81F", "r' c #FFCB24", "s' c #FDAB1F", "t' c #FA9F1E", "u' c #F79218", "v' c #E7831A", "w' c #A45126", "x' c #73352E", "y' c #80472A", "z' c #7D4329", "A' c #000D1A", "B' c #001C3B", "C' c #00376E", "D' c #055DA9", "E' c #1485D3", "F' c #219BE3", "G' c #259AE1", "H' c #2498DE", "I' c #26A0E0", "J' c #27A4E1", "K' c #28A3E1", "L' c #28A5E2", "M' c #27A1E0", "N' c #29A2DF", "O' c #2DAAE1", "P' c #2DACE1", "Q' c #2CA7DD", "R' c #2EA8DC", "S' c #2EAADC", "T' c #30AFDF", "U' c #31AEDD", "V' c #31AAD9", "W' c #30A5D6", "X' c #2F9BCE", "Y' c #2E99CC", "Z' c #2F99CB", "`' c #3098C8", " ) c #3094C5", ".) c #3194C6", "+) c #3294C5", "@) c #3593C7", "#) c #3794C8", "$) c #3691C6", "%) c #3790C8", "&) c #3D9AD8", "*) c #41B9F2", "=) c #5DE3FF", "-) c #C7FFFF", ";) c #C2F3FD", ">) c #40ABDC", ",) c #2475AD", "') c #3172A3", ")) c #2E72A3", "!) c #2C70A1", "~) c #2D70A1", "{) c #2D71A1", "]) c #2B70A0", "^) c #2A6D9C", "/) c #296F9F", "() c #2A73A4", "_) c #286C9E", ":) c #276A99", "<) c #256897", "[) c #1E6294", "}) c #1865A1", "|) c #1F6DAD", "1) c #47789E", "2) c #8A8875", "3) c #C79F4E", "4) c #EAAA35", "5) c #F49F28", "6) c #F59321", "7) c #FBA223", "8) c #FFAF24", "9) c #FEA520", "0) c #FE9219", "a) c #FEBB22", "b) c #FFCE27", "c) c #FFCF27", "d) c #FFD024", "e) c #FFCD25", "f) c #F08617", "g) c #E98017", "h) c #FAA01D", "i) c #F99F22", "j) c #AE5E29", "k) c #70392A", "l) c #804B28", "m) c #7D4727", "n) c #00060B", "o) c #00101F", "p) c #002145", "q) c #01407F", "r) c #096CBB", "s) c #188EDE", "t) c #2399E4", "u) c #2399E0", "v) c #259CE1", "w) c #269FE3", "x) c #26A1E3", "y) c #28A5E4", "z) c #2BA9E6", "A) c #2CAEE8", "B) c #2EB1E6", "C) c #2DB1E6", "D) c #31B7E8", "E) c #33BCE9", "F) c #36BDE7", "G) c #3BC1E5", "H) c #37BEE6", "I) c #33B9E4", "J) c #33B4E1", "K) c #35B4DF", "L) c #36B3DD", "M) c #32A5D4", "N) c #31A1D2", "O) c #309BCE", "P) c #2F97C9", "Q) c #3096C8", "R) c #3296C6", "S) c #3496C7", "T) c #399BCC", "U) c #3897C9", "V) c #358EC1", "W) c #368CC1", "X) c #3893CF", "Y) c #46B8EC", "Z) c #87F0FF", "`) c #E3FFFF", " ! c #B1E9F9", ".! c #3AA0D9", "+! c #2B79B2", "@! c #3277A7", "#! c #3074A5", "$! c #2F73A4", "%! c #3075A7", "&! c #3079AB", "*! c #317BAC", "=! c #2E73A2", "-! c #2A6C9C", ";! c #2A6E9E", ">! c #2A6E9F", ",! c #266A99", "'! c #286898", ")! c #246595", "!! c #19629A", "~! c #1566A8", "{! c #3575A7", "]! c #7A8A84", "^! c #BB9B55", "/! c #E29D36", "(! c #F29E28", "_! c #FBAD25", ":! c #FFB024", "~ c #FFCA25", ",~ c #FFCD22", "'~ c #FFD625", ")~ c #FFD229", "!~ c #FFC026", "~~ c #FD9C21", "{~ c #FCA322", "]~ c #FFB524", "^~ c #F7A41F", "/~ c #AB6125", "(~ c #73392C", "_~ c #7F442A", ":~ c #7D4428", "<~ c #001226", "[~ c #002752", "}~ c #024C92", "|~ c #107CCC", "1~ c #2099E5", "2~ c #259DE5", "3~ c #25A0E4", "4~ c #27AAE8", "5~ c #29ACE9", "6~ c #2AADEA", "7~ c #2DB4ED", "8~ c #30BAEF", "9~ c #33C0F0", "0~ c #32C0EF", "a~ c #34C1F0", "b~ c #37C5F0", "c~ c #35C0EF", "d~ c #33BCED", "e~ c #33BBEC", "f~ c #34BBEA", "g~ c #33BAE9", "h~ c #34B9E7", "i~ c #33B7E4", "j~ c #32B5E2", "k~ c #33B2DF", "l~ c #33B1DD", "m~ c #33AFDC", "n~ c #35AEDB", "o~ c #34A9D7", "p~ c #35A4D4", "q~ c #35A2D1", "r~ c #359DCE", "s~ c #3599CA", "t~ c #3797C9", "u~ c #3895C8", "v~ c #3A95C8", "w~ c #3795CD", "x~ c #3FA8E2", "y~ c #9BE8FD", "z~ c #DFFFFF", "A~ c #72D4F7", "B~ c #33ACEA", "C~ c #3DA1E1", "D~ c #3688C2", "E~ c #3578AB", "F~ c #3378A9", "G~ c #3177A6", "H~ c #3276A7", "I~ c #3077A6", "J~ c #2F75A4", "K~ c #2E73A3", "L~ c #2F77A6", "M~ c #2F78A9", "N~ c #2A6C9D", "O~ c #2B71A2", "P~ c #2C78A8", "Q~ c #2972A4", "R~ c #256694", "S~ c #1D5F90", "T~ c #1362A3", "U~ c #2673B1", "V~ c #638493", "W~ c #AC935C", "X~ c #DDA639", "Y~ c #F3A726", "Z~ c #FDA21D", "`~ c #FEA31D", " { c #FEA31C", ".{ c #FEB41C", "+{ c #FFC921", "@{ c #FFD426", "#{ c #FFD92E", "${ c #FFC827", "%{ c #FDAF23", "&{ c #FF9E20", "*{ c #FF9C1D", "={ c #F9B023", "-{ c #B17C26", ";{ c #734525", ">{ c #814628", ",{ c #7E4428", "'{ c #000002", "){ c #001326", "!{ c #002755", "~{ c #034E97", "{{ c #127ECF", "]{ c #219CE6", "^{ c #249FE4", "/{ c #25A3E4", "({ c #26ACE8", "_{ c #28B1EB", ":{ c #2AB0ED", "<{ c #2CB0EE", "[{ c #2FB7F0", "}{ c #32BBF2", "|{ c #33BFF1", "1{ c #35BEF2", "2{ c #36C0F1", "3{ c #37C2F1", "4{ c #38C5F0", "5{ c #38C5EF", "6{ c #38C5EE", "7{ c #36C3EC", "8{ c #37C1EB", "9{ c #37C0E9", "0{ c #36BEE7", "a{ c #38BCE4", "b{ c #37BAE3", "c{ c #37B6E1", "d{ c #36B1DD", "e{ c #36AFDC", "f{ c #37A9D8", "g{ c #36A5D4", "h{ c #37A2D2", "i{ c #379FD1", "j{ c #389CCD", "k{ c #3897C8", "l{ c #3796C7", "m{ c #3994C6", "n{ c #388FC3", "o{ c #3592C9", "p{ c #5CBCE8", "q{ c #B2F3FE", "r{ c #C7FEFF", "s{ c #AFEFFF", "t{ c #8ADCFB", "u{ c #43ABE4", "v{ c #2A7EBD", "w{ c #3478AC", "x{ c #367BAB", "y{ c #3479AA", "z{ c #357DAF", "A{ c #347EB1", "B{ c #3076A6", "C{ c #2E73A1", "D{ c #2C72A2", "E{ c #2E7AA9", "F{ c #2D7AAB", "G{ c #2A73A5", "H{ c #27699A", "I{ c #206295", "J{ c #1465A4", "K{ c #206FB0", "L{ c #5D8594", "M{ c #AA9E5F", "N{ c #DCA939", "O{ c #F4A625", "P{ c #FD9C1B", "Q{ c #FFA01B", "R{ c #FEAE21", "S{ c #FEAF22", "T{ c #FEAF1C", "U{ c #FFCE24", "V{ c #FFD92D", "W{ c #FFCB30", "X{ c #F9961F", "Y{ c #FDA620", "Z{ c #FFAF1F", "`{ c #F9BC27", " ] c #B18128", ".] c #704224", "+] c #824926", "@] c #804A25", "#] c #00050A", "$] c #001122", "%] c #002852", "&] c #035297", "*] c #1381D2", "=] c #2399E6", "-] c #239CE3", ";] c #229CE2", ">] c #2BB5EC", ",] c #2BB2ED", "'] c #2DB2F0", ")] c #30B9F1", "!] c #32BCF2", "~] c #34BFF4", "{] c #36C3F5", "]] c #3AC7F5", "^] c #3DCAF6", "/] c #3DCAF5", "(] c #3DCBF5", "_] c #3DCDF4", ":] c #3ECEF3", "<] c #3DCEF2", "[] c #3CCDF0", "}] c #3BCAEF", "|] c #3CC9EE", "1] c #3BC5EC", "2] c #3AC1E8", "3] c #3ABEE7", "4] c #39B9E4", "5] c #38B6E1", "6] c #39B3DF", "7] c #39ADDA", "8] c #37A6D6", "9] c #37A3D2", "0] c #38A0D0", "a] c #389ECF", "b] c #3998C9", "c] c #3A91C3", "d] c #388CC0", "e] c #3591CB", "f] c #55B6E4", "g] c #9AE2F5", "h] c #D0F5FE", "i] c #E2FFFF", "j] c #9FE7FB", "k] c #44B1E4", "l] c #3493CC", "m] c #3A86BC", "n] c #387DB0", "o] c #367DAE", "p] c #367FB0", "q] c #3379AA", "r] c #3075A4", "s] c #2F73A2", "t] c #2F72A2", "u] c #2C71A0", "v] c #2B6F9F", "w] c #2F7AA8", "x] c #3183B1", "y] c #2C76A9", "z] c #286A9D", "A] c #236798", "B] c #1E6EAF", "C] c #5D8792", "D] c #AD9F5D", "E] c #DFA735", "F] c #F5A524", "G] c #FDAA21", "H] c #FEAD20", "I] c #FEAA1E", "J] c #FEAD1D", "K] c #FFDA28", "L] c #FFD428", "M] c #FE9B1B", "N] c #FEB92A", "O] c #FEB725", "P] c #F7A721", "Q] c #A65E29", "R] c #61282F", "S] c #6E362A", "T] c #6D3928", "U] c #00101D", "V] c #00244A", "W] c #024D90", "X] c #1381CF", "Y] c #239DE6", "Z] c #259FE3", "`] c #24A1E6", " ^ c #2AB2EB", ".^ c #2FBCEF", "+^ c #2FB9F0", "@^ c #31B9F2", "#^ c #36C2F3", "$^ c #38C6F5", "%^ c #3BC9F7", "&^ c #3DCCF8", "*^ c #41D1F8", "=^ c #44D3F8", "-^ c #43D3F7", ";^ c #44D3F7", ">^ c #44D4F7", ",^ c #44D4F6", "'^ c #42D2F5", ")^ c #40D0F3", "!^ c #40CDF2", "~^ c #3ECCF1", "{^ c #3DC9EF", "]^ c #3CC5EC", "^^ c #3BC0E8", "/^ c #3ABCE5", "(^ c #39B8E3", "_^ c #3BB5E0", ":^ c #39AFDC", "<^ c #39AAD8", "[^ c #39A7D6", "}^ c #3AA4D5", "|^ c #3AA1D2", "1^ c #3A9ED1", "2^ c #3B9BCE", "3^ c #3B97C9", "4^ c #3B97C8", "5^ c #3E93C7", "6^ c #398CC3", "7^ c #328AC5", "8^ c #3797D1", "9^ c #54B1E7", "0^ c #A6E1FC", "a^ c #E7FFFF", "b^ c #B8F3FE", "c^ c #5DC9F4", "d^ c #3695D6", "e^ c #397FB6", "f^ c #377CAC", "g^ c #357BAB", "h^ c #3378A8", "i^ c #3176A7", "j^ c #327AAB", "k^ c #337DAF", "l^ c #2E74A4", "m^ c #2A6C9B", "n^ c #2C72A1", "o^ c #327FAE", "p^ c #2C77AA", "q^ c #2A6D9D", "r^ c #256A9B", "s^ c #2172B3", "t^ c #668B91", "u^ c #B59F56", "v^ c #E3AF36", "w^ c #F8B029", "x^ c #FFA41A", "y^ c #FFBB24", "z^ c #FFC422", "A^ c #FFE029", "B^ c #FFC31F", "C^ c #FFA21B", "D^ c #FFB728", "E^ c #A85229", "F^ c #5E1F32", "G^ c #5D252E", "H^ c #000306", "I^ c #000C18", "J^ c #002142", "K^ c #014789", "L^ c #0F79C9", "M^ c #2096E2", "N^ c #239AE0", "O^ c #229DE2", "P^ c #24A2E6", "Q^ c #29B1EB", "R^ c #2FC2F1", "S^ c #31C3F3", "T^ c #33C0F3", "U^ c #37C4F4", "V^ c #3DCEF9", "W^ c #42D0F8", "X^ c #44D2FA", "Y^ c #47D6FA", "Z^ c #4AD6FA", "`^ c #4BD7F9", " / c #4AD6F8", "./ c #47D4F7", "+/ c #45D3F5", "@/ c #44CFF3", "#/ c #42CEF2", "$/ c #41CCF0", "%/ c #3EC8EE", "&/ c #3CC3EA", "*/ c #3BC0E7", "=/ c #3BBCE5", "-/ c #3CB7E2", ";/ c #3AB4E0", ">/ c #3BAFDD", ",/ c #3AABDA", "'/ c #3AA7D8", ")/ c #3CA5D6", "!/ c #3CA2D5", "~/ c #3D9ED0", "{/ c #3D9ACC", "]/ c #3D98CA", "^/ c #3E96C9", "// c #3E92C5", "(/ c #3D8CC0", "_/ c #3486BE", ":/ c #2D8ACB", "( c #3D97CB", ",( c #3D94C7", "'( c #3E91C4", ")( c #4090C3", "!( c #418EC3", "~( c #358CC9", "{( c #3BA4E3", "]( c #93DDFB", "^( c #B1E8F9", "/( c #42A3DA", "(( c #2F7EB9", "_( c #3A7FB0", ":( c #387FAF", "<( c #377EAF", "[( c #3A86B4", "}( c #3C8BBB", "|( c #3881B4", "1( c #3379AC", "2( c #3278AA", "3( c #3179AA", "4( c #2F77A7", "5( c #2D72A1", "6( c #266898", "7( c #286D9D", "8( c #2E78A4", "9( c #256E9E", "0( c #1364A9", "a( c #2E75A9", "b( c #818B7A", "c( c #CB9845", "d( c #EFAB2D", "e( c #FDBD27", "f( c #FEC622", "g( c #FD9220", "h( c #FB8E21", "i( c #F59C21", "j( c #F4961D", "k( c #FDA022", "l( c #FFA322", "m( c #FA951F", "n( c #EF8B1B", "o( c #E3881D", "p( c #E28A1F", "q( c #CD791F", "r( c #834027", "s( c #4D172F", "t( c #51212B", "u( c #4E202A", "v( c #00152A", "w( c #003367", "x( c #0863B2", "y( c #1B8BD9", "z( c #2195DC", "A( c #24A1DF", "B( c #2AB1E6", "C( c #2AB3EA", "D( c #2CBBEF", "E( c #30C6F2", "F( c #3CC9F3", "G( c #46D4F6", "H( c #41D3F8", "I( c #3ECDFA", "J( c #45CFFA", "K( c #4CD5FB", "L( c #51D8FD", "M( c #55D9FD", "N( c #5ADBFD", "O( c #5EDAFD", "P( c #5FDAFD", "Q( c #5EDBFD", "R( c #5CD9FC", "S( c #5AD9FB", "T( c #55D8FA", "U( c #50D6F9", "V( c #4DD5F8", "W( c #49D3F6", "X( c #46D0F5", "Y( c #44CEF3", "Z( c #42C9F1", "`( c #47CCF2", " _ c #49CAEE", "._ c #3DBEE8", "+_ c #3EB9E5", "@_ c #3EB5E2", "#_ c #3DB0DE", "$_ c #3DACDB", "%_ c #3DA8D8", "&_ c #3DA6D5", "*_ c #3DA1D4", "=_ c #3D9ED1", "-_ c #3F9ACF", ";_ c #3F98CB", ">_ c #4195C9", ",_ c #3F94C8", "'_ c #4092C8", ")_ c #4191C5", "!_ c #418DC2", "~_ c #3A8ECC", "{_ c #41A2E1", "]_ c #84D3F5", "^_ c #C5FCFF", "/_ c #9BE7FA", "(_ c #4BA6DD", "__ c #3786BE", ":_ c #3A83B2", "<_ c #387EAF", "[_ c #377DAF", "}_ c #3780B2", "|_ c #377FB3", "1_ c #357CAD", "2_ c #3680B1", "3_ c #3581B4", "4_ c #327CAD", "5_ c #3077A7", "6_ c #2D71A2", "7_ c #2B74A4", "8_ c #286795", "9_ c #155991", "0_ c #0858A5", "a_ c #3A6E9C", "b_ c #96916A", "c_ c #D8AE40", "d_ c #F6BC2D", "e_ c #FBAF21", "f_ c #FB961A", "g_ c #FC921F", "h_ c #FD9722", "i_ c #FA9F22", "j_ c #F89C20", "k_ c #FE9A20", "l_ c #FEA221", "m_ c #FCA623", "n_ c #F79C21", "o_ c #EF9020", "p_ c #E98A1E", "q_ c #D1771E", "r_ c #833F27", "s_ c #45142E", "t_ c #54252B", "u_ c #55272A", "v_ c #002853", "w_ c #0558A1", "x_ c #1785D3", "y_ c #2291D9", "z_ c #2194D9", "A_ c #28ADE4", "B_ c #2EC0EB", "C_ c #2BB6EB", "D_ c #2BB7EF", "E_ c #32C4F3", "F_ c #40CFF6", "G_ c #47D5F8", "H_ c #40CEF9", "I_ c #42CEFB", "J_ c #4CD3FC", "K_ c #53D8FC", "L_ c #61DBFD", "M_ c #66DDFE", "N_ c #6ADCFE", "O_ c #6BDBFD", "P_ c #6ADCFD", "Q_ c #69DBFD", "R_ c #63DAFD", "S_ c #5DD9FC", "T_ c #58D8FB", "U_ c #53D7FA", "V_ c #4FD5F8", "W_ c #4AD3F7", "X_ c #49D0F5", "Y_ c #43CCF3", "Z_ c #4FD2F5", "`_ c #51D0F2", " : c #3FC0EA", ".: c #3FBAE7", "+: c #3FB6E2", "@: c #3FB2DF", "#: c #3FAEDF", "$: c #3FACDC", "%: c #3FA8D9", "&: c #40A3D6", "*: c #3FA0D3", "=: c #419DD3", "-: c #439DD3", ";: c #439BCF", ">: c #4196CB", ",: c #4294C9", "': c #4291C7", "): c #4290C5", "!: c #458FC3", "~: c #3B8AC6", "{: c #3293D4", "]: c #78CFF0", "^: c #93DCFA", "/: c #3A9BDD", "(: c #3D88C1", "_: c #3D86B7", ":: c #3A81B4", "<: c #387DB1", "[: c #357CAC", "}: c #3780B0", "|: c #347DAE", "1: c #3279AB", "2: c #327CAF", "3: c #2E77AA", "4: c #3282AF", "5: c #2D79AD", "6: c #256DA8", "7: c #2877AC", "8: c #1D75B4", "9: c #1368B6", "0: c #4F7890", "a: c #AB9B59", "b: c #E4B438", "c: c #FAC328", "d: c #FFA420", "e: c #FC9322", "f: c #F2811B", "g: c #F7911D", "h: c #FFC128", "i: c #FCA523", "j: c #FD9E21", "k: c #FA951C", "l: c #FEA822", "m: c #FEA723", "n: c #FE9A22", "o: c #FD9C22", "p: c #F19222", "q: c #8F4729", "r: c #411330", "s: c #55262B", "t: c #57282A", "u: c #000103", "v: c #000A13", "w: c #014687", "x: c #117AC9", "y: c #2192D9", "z: c #2091D8", "A: c #2198DD", "B: c #27ABE5", "C: c #29B4EA", "D: c #29AFEB", "E: c #2BB3EE", "F: c #3ACCF6", "G: c #3DCDF8", "H: c #41CEFA", "I: c #49D3FC", "J: c #53D7FD", "K: c #5BD9FE", "L: c #64DBFE", "M: c #6EDDFE", "N: c #74DEFE", "O: c #77DEFF", "P: c #78DEFE", "Q: c #79DEFD", "R: c #74DDFE", "S: c #6DDCFE", "T: c #67DBFD", "U: c #60DAFC", "V: c #58D6FB", "W: c #52D6FA", "X: c #4DD4F8", "Y: c #4AD2F6", "Z: c #46CEF3", "`: c #48CEF2", " < c #47CAF1", ".< c #42C2EC", "+< c #41BCE8", "@< c #41B8E3", "#< c #41B4E2", "$< c #41B0E0", "%< c #41ADDF", "&< c #41AADD", "*< c #42A6D9", "=< c #41A2D5", "-< c #429ED5", ";< c #449ED3", ">< c #439CD1", ",< c #4397CB", "'< c #4394CA", ")< c #4594CC", "!< c #4495CD", "~< c #4592C8", "{< c #428BC0", "]< c #307FBC", "^< c #46A0D8", "/< c #C4F0FC", "(< c #CAF9FF", "_< c #53B7F2", ":< c #3E93D5", "<< c #4797C5", "[< c #3F8BBA", "}< c #387FB2", "|< c #387EAE", "1< c #367DAC", "2< c #367AAB", "3< c #3377A7", "4< c #3175A6", "5< c #337AAC", "6< c #2673AA", "7< c #1F70B0", "8< c #439DD2", "9< c #83D8ED", "0< c #86E1EF", "a< c #48BAEB", "b< c #2F8AC5", "c< c #708880", "d< c #C2A44A", "e< c #EDB62D", "f< c #FCB622", "g< c #FFA722", "h< c #F98B1F", "i< c #F5851E", "j< c #FCA022", "k< c #F5B223", "l< c #EC9A1B", "m< c #FA931F", "n< c #F99920", "o< c #FB9D1F", "p< c #FB9A1E", "q< c #FEA021", "r< c #FC9C21", "s< c #FA9520", "t< c #FE9E21", "u< c #F49522", "v< c #995029", "w< c #4A1931", "x< c #56262D", "y< c #56252C", "z< c #001429", "A< c #00356C", "B< c #0A66B5", "C< c #1C88D4", "D< c #2290D4", "E< c #2196D9", "F< c #239EDF", "G< c #26A3E2", "H< c #27A9E7", "I< c #2AB0EC", "J< c #2EB9F1", "K< c #34C3F4", "L< c #39C9F6", "M< c #45D2FA", "N< c #4ED7FB", "O< c #58D9FD", "P< c #62DBFE", "Q< c #6DDBFE", "R< c #77DEFE", "S< c #80E0FE", "T< c #84E0FE", "U< c #85E0FE", "V< c #84DFFF", "W< c #7FDEFE", "X< c #78DDFE", "Y< c #6FDCFE", "Z< c #67DBFC", "`< c #5ED7FC", " [ c #55D7FA", ".[ c #4FD4F9", "+[ c #4BD3F6", "@[ c #48D0F4", "#[ c #45CBF0", "$[ c #42C7EF", "%[ c #44C3ED", "&[ c #42BEE9", "*[ c #42BAE7", "=[ c #41B6E5", "-[ c #42B1E1", ";[ c #42ADDF", ">[ c #41ABDE", ",[ c #42A8DB", "'[ c #43A4D8", ")[ c #439FD5", "![ c #439DD1", "~[ c #439BD1", "{[ c #4497CE", "][ c #4396CD", "^[ c #4698CF", "/[ c #4698D1", "([ c #4593CB", "_[ c #438EC5", ":[ c #3C86BF", "<[ c #3C90CE", "[[ c #98D5F4", "}[ c #D2FFFF", "|[ c #6BC5F4", "1[ c #3A93D8", "2[ c #4895C8", "3[ c #408CBD", "4[ c #3A82B3", "5[ c #3A81B3", "6[ c #387FB0", "7[ c #3579A9", "8[ c #3376A5", "9[ c #3374A2", "0[ c #2E72A6", "a[ c #2772B0", "b[ c #2D7CBD", "c[ c #3FA2D7", "d[ c #74E6FA", "e[ c #9CFAFF", "f[ c #84E3FA", "g[ c #6CE6FF", "h[ c #48CCFC", "i[ c #4697BC", "j[ c #909169", "k[ c #D5A438", "l[ c #F5B128", "m[ c #FC961B", "n[ c #FFA523", "o[ c #E5881C", "p[ c #D37C1A", "q[ c #E3851E", "r[ c #EE8E1F", "s[ c #FB9D20", "t[ c #FFA623", "u[ c #FF9F21", "v[ c #F4901F", "w[ c #EA8A1E", "x[ c #EF911F", "y[ c #E88A1F", "z[ c #A35627", "A[ c #5E252E", "B[ c #642E2D", "C[ c #642D2C", "D[ c #000D19", "E[ c #00264D", "F[ c #04529B", "G[ c #177ECC", "H[ c #228BD2", "I[ c #218FD3", "J[ c #239ADB", "K[ c #25A6E1", "L[ c #28ABE4", "M[ c #29ADE8", "N[ c #2CB4ED", "O[ c #30BFF2", "P[ c #35C5F6", "Q[ c #3CCFF8", "R[ c #43D4FA", "S[ c #49D4FC", "T[ c #5DD9FD", "U[ c #69DAFE", "V[ c #8AE1FE", "W[ c #8FE1FE", "X[ c #91E2FE", "Y[ c #90E1FE", "Z[ c #77DEFD", "`[ c #62D9FC", " } c #51D6F9", ".} c #4ED3F8", "+} c #49D0F6", "@} c #48CDF3", "#} c #46C9F1", "$} c #45C5EE", "%} c #44C0EC", "&} c #44BBE9", "*} c #43B7E7", "=} c #42B3E2", "-} c #42AFE1", ";} c #44ADDE", ">} c #44A8DB", ",} c #44A4DA", "'} c #43A1D8", ")} c #449FD5", "!} c #459BD2", "~} c #469AD1", "{} c #4599D1", "]} c #4799D0", "^} c #4796CE", "/} c #4793CB", "(} c #4893CB", "_} c #4898CE", ":} c #4097D1", "<} c #74C7ED", "[} c #C3FFFF", "}} c #7BD0F6", "|} c #3593DA", "1} c #448DC9", "2} c #428CC1", "3} c #3C86B8", "4} c #3C83B5", "5} c #397FB0", "6} c #387DAC", "7} c #3277A8", "8} c #246FA9", "9} c #217BBB", "0} c #53ACDB", "a} c #88DEF3", "b} c #77E4FD", "c} c #5BCBED", "d} c #48A6D3", "e} c #338AC7", "f} c #3F9BCD", "g} c #3EB2E8", "h} c #2897DE", "i} c #5B8796", "j} c #B29551", "k} c #E7A22F", "l} c #FFA923", "m} c #F09220", "n} c #E68B1F", "o} c #E28D1E", "p} c #EC931F", "q} c #F99A20", "r} c #FEA323", "s} c #FD9F24", "t} c #EA881E", "u} c #D87E1B", "v} c #E3891C", "w} c #E8891D", "x} c #A65628", "y} c #60252F", "z} c #70322D", "A} c #73352A", "B} c #001833", "C} c #013E7A", "D} c #0D6DBC", "E} c #1F87CF", "F} c #228ECF", "G} c #2292D5", "H} c #2297DA", "I} c #26A9E1", "J} c #2AB6E8", "K} c #2CB1EA", "L} c #2EB7EE", "M} c #32C3F2", "N} c #37C7F5", "O} c #3FD0F8", "P} c #46D6FA", "Q} c #4DD7FC", "R} c #56D8FD", "S} c #61DAFD", "T} c #7ADEFE", "U} c #88E1FE", "V} c #92E3FE", "W} c #98E4FE", "X} c #99E3FE", "Y} c #98E3FE", "Z} c #87E1FE", "`} c #7BDFFD", " | c #70DCFD", ".| c #65D9FC", "+| c #5BD7FB", "@| c #53D6FA", "#| c #50D3F8", "$| c #4BD0F6", "%| c #49CDF4", "&| c #47CAF2", "*| c #45C6EE", "=| c #45C0ED", "-| c #45BDEB", ";| c #44BAE9", ">| c #45B6E5", ",| c #44B2E3", "'| c #45AEE1", ")| c #45AADE", "!| c #44A7DC", "~| c #46A4DB", "{| c #47A1D9", "]| c #479DD4", "^| c #489DD4", "/| c #489BD4", "(| c #4897D0", "_| c #4895CD", ":| c #4894CD", "<| c #4A97CE", "[| c #4C9ED3", "}| c #449AD5", "|| c #5EBEEB", "1| c #C7FCFF", "2| c #B4EDFD", "3| c #4EB5ED", "4| c #4195D6", "5| c #448EC5", "6| c #3E87BA", "7| c #3C84B5", "8| c #3B84B5", "9| c #3B83B5", "0| c #3B84B8", "a| c #348BC7", "b| c #3B99D7", "c| c #6CC5EC", "d| c #A1F7FF", "e| c #94EEFC", "f| c #55B5E0", "g| c #2C84C0", "h| c #2471AC", "i| c #236AA2", "j| c #2469A1", "k| c #2873AD", "l| c #1876C1", "m| c #2F79B1", "n| c #858774", "o| c #CF943E", "p| c #F4A428", "q| c #FEA922", "r| c #FEAD23", "s| c #FEAE25", "t| c #FDA623", "u| c #F7A120", "v| c #FAA422", "w| c #FC9F21", "x| c #FF9F22", "y| c #F59322", "z| c #E5831F", "A| c #D67C1B", "B| c #EA8C1B", "C| c #F5951E", "D| c #AA5A27", "E| c #642530", "F| c #79342C", "G| c #7D382A", "H| c #000E1B", "I| c #002B56", "J| c #0658A1", "K| c #177DC8", "L| c #2187CA", "M| c #218ECE", "N| c #2293D5", "O| c #259DDB", "P| c #2AB1E4", "Q| c #2BB4E8", "R| c #2BB0EA", "S| c #2FB8ED", "T| c #33C3F2", "U| c #37C9F5", "V| c #3ECEF7", "W| c #46D4FA", "X| c #4ED7FC", "Y| c #57D8FD", "Z| c #63D9FE", "`| c #70DBFE", " 1 c #8BE1FE", ".1 c #95E3FF", "+1 c #9CE5FF", "@1 c #9EE4FF", "#1 c #9CE4FE", "$1 c #96E3FE", "%1 c #7EDEFE", "&1 c #73DDFE", "*1 c #68DAFC", "=1 c #5DD8FB", "-1 c #56D5FA", ";1 c #50D4F8", ">1 c #4CD1F7", ",1 c #4ACEF4", "'1 c #47C6F1", ")1 c #47C2EE", "!1 c #46BFEC", "~1 c #47BEEC", "{1 c #49BBEA", "]1 c #47B5E5", "^1 c #45B0E3", "/1 c #45ABE1", "(1 c #46A8DE", "_1 c #48A6DC", ":1 c #48A3DA", "<1 c #48A0D6", "[1 c #499DD6", "}1 c #499BD4", "|1 c #4896D0", "11 c #4995CE", "21 c #4997D0", "31 c #4A97D0", "41 c #4996CE", "51 c #4595D4", "61 c #52B4ED", "71 c #A9EEFF", "81 c #E5FFFF", "91 c #8EE1FB", "01 c #42A5E3", "a1 c #418CC8", "b1 c #4088BC", "c1 c #3D84B6", "d1 c #3D86B9", "e1 c #3D8AC0", "f1 c #3E96D5", "g1 c #5EBCEF", "h1 c #A6E7FC", "i1 c #C5FEFF", "j1 c #86D8EE", "k1 c #3D93C6", "l1 c #2975AF", "m1 c #2C74AD", "n1 c #2F7AAF", "o1 c #2D73A2", "p1 c #276A9C", "q1 c #266698", "r1 c #1D6399", "s1 c #1667AE", "t1 c #527B95", "u1 c #AC8B58", "v1 c #E4942F", "w1 c #FBA123", "x1 c #FEA023", "y1 c #FFAF25", "z1 c #FFAD24", "A1 c #FFA423", "B1 c #FFA023", "C1 c #FD9820", "D1 c #F59320", "E1 c #F08C1F", "F1 c #E5871B", "G1 c #EF8F1B", "H1 c #F6971F", "I1 c #A65228", "J1 c #692231", "K1 c #7D312D", "L1 c #7D312C", "M1 c #001A34", "N1 c #01407E", "O1 c #0F6EBA", "P1 c #2188C9", "Q1 c #2390CD", "R1 c #2290D0", "S1 c #2393D3", "T1 c #2AA7DE", "U1 c #2DB7E6", "V1 c #2AB0E6", "W1 c #2BB0E8", "X1 c #2FBCEE", "Y1 c #34C5F3", "Z1 c #38CAF5", "`1 c #3DCFF8", " 2 c #44D3FA", ".2 c #4DD5FC", "+2 c #57D7FD", "@2 c #63D9FD", "#2 c #95E2FF", "$2 c #9CE4FF", "%2 c #9FE4FE", "&2 c #9BE3FE", "*2 c #94E3FE", "=2 c #8AE0FE", "-2 c #80DEFE", ";2 c #57D6FA", ">2 c #4CD0F7", ",2 c #4ACEF5", "'2 c #49CBF3", ")2 c #49C8F3", "!2 c #47C4EF", "~2 c #47BDEB", "{2 c #4AB9EB", "]2 c #4AB6E8", "^2 c #49B2E5", "/2 c #48ADE3", "(2 c #47A8DF", "_2 c #49A7DC", ":2 c #49A4DB", "<2 c #48A1D9", "[2 c #4A9DD7", "}2 c #499BD5", "|2 c #4B99D3", "12 c #4A98D1", "22 c #4999D2", "32 c #4B9AD3", "42 c #4B98D3", "52 c #4996D3", "62 c #47A1E3", "72 c #78D2FA", "82 c #B6EEFC", "92 c #45A7E2", "02 c #3E8AC6", "a2 c #438CBF", "b2 c #4089BC", "c2 c #3F8ABF", "d2 c #3B8AC7", "e2 c #40A2DF", "f2 c #9BE5FD", "g2 c #DCFFFF", "h2 c #8CD8F3", "i2 c #3991C7", "j2 c #256DA4", "k2 c #2F74A5", "l2 c #317AAB", "m2 c #2E78A8", "n2 c #276A9B", "o2 c #266691", "p2 c #1461A0", "q2 c #2870A9", "r2 c #808175", "s2 c #CE873C", "t2 c #F49826", "u2 c #FEA022", "v2 c #FE9320", "w2 c #FEA223", "x2 c #FEA224", "y2 c #FA991F", "z2 c #FC9A20", "A2 c #F7921B", "B2 c #F5901C", "C2 c #EE8D1D", "D2 c #A14E2A", "E2 c #6A1F33", "F2 c #7E302E", "G2 c #7C312D", "H2 c #000E1A", "I2 c #002A55", "J2 c #0657A1", "K2 c #187BC3", "L2 c #258CC6", "M2 c #2597CF", "N2 c #2395D1", "O2 c #2396D3", "P2 c #28A4DC", "Q2 c #2AABE2", "R2 c #2AACE4", "S2 c #2CB3E8", "T2 c #32BFEE", "U2 c #37C9F2", "V2 c #39CCF4", "W2 c #3DCEF8", "X2 c #56D7FC", "Y2 c #61D8FD", "Z2 c #6EDAFD", "`2 c #7ADCFE", " 3 c #87DFFE", ".3 c #91E1FE", "+3 c #97E4FE", "@3 c #9AE4FE", "#3 c #97E2FE", "$3 c #90E0FE", "%3 c #86DEFE", "&3 c #7CDDFD", "*3 c #70DDFD", "=3 c #64D9FC", "-3 c #5CD7FB", ";3 c #55D5FA", ">3 c #4DD0F7", ",3 c #4BCEF5", "'3 c #4BCBF3", ")3 c #4BC9F3", "!3 c #4AC4F0", "~3 c #49BFEC", "{3 c #48BBEB", "]3 c #46B6E9", "^3 c #3CACE5", "/3 c #3DA7E3", "(3 c #48AAE1", "_3 c #4BACDF", ":3 c #4AA9E0", "<3 c #49A5DD", "[3 c #4AA2DC", "}3 c #4CA0D9", "|3 c #4C9ED8", "13 c #4B9DD6", "23 c #4C9AD4", "33 c #4D9DD8", "43 c #4E9DD9", "53 c #4D96D7", "63 c #4299E4", "73 c #7BD0FA", "83 c #A4E0F9", "93 c #409DD9", "03 c #3F89C4", "a3 c #4791C6", "b3 c #448EC3", "c3 c #428BBF", "d3 c #3A84BF", "e3 c #3D99D1", "f3 c #91E2F6", "g3 c #6AC0EB", "h3 c #2E88C3", "i3 c #327AA9", "j3 c #3174A2", "k3 c #2E71A1", "l3 c #2D73A3", "m3 c #2D73A7", "n3 c #2B6EA1", "o3 c #2871A2", "p3 c #296E9D", "q3 c #1466A8", "r3 c #527391", "s3 c #AE8354", "t3 c #E78F2E", "u3 c #FB9B23", "v3 c #FE9D22", "w3 c #FEA522", "x3 c #FEA524", "y3 c #FCA223", "z3 c #F89A20", "A3 c #FE9F1F", "B3 c #FE9B1F", "C3 c #F38D1B", "D3 c #AB6226", "E3 c #71322F", "F3 c #80392D", "G3 c #7E392C", "H3 c #001930", "I3 c #013E78", "J3 c #0E6BB7", "K3 c #2080C1", "L3 c #2285C1", "M3 c #228ECA", "N3 c #2291CD", "O3 c #2395D2", "P3 c #27A2DC", "Q3 c #29A8E0", "R3 c #2BABE3", "S3 c #2DB3E8", "T3 c #31BEED", "U3 c #36C8F1", "V3 c #38CCF4", "W3 c #3DCFF7", "X3 c #43D2F9", "Y3 c #4AD5FB", "Z3 c #52D6FC", "`3 c #5DD6FD", " 4 c #68D8FD", ".4 c #73DBFE", "+4 c #7EDDFE", "@4 c #89E0FE", "#4 c #8DE1FE", "$4 c #88DFFE", "%4 c #80DEFD", "&4 c #75DDFD", "*4 c #6BDAFD", "=4 c #61D7FC", "-4 c #5AD5FB", ";4 c #54D4FA", ">4 c #4FD2F8", ",4 c #4CCEF5", "'4 c #4BCBF4", ")4 c #4AC8F2", "!4 c #4BC3F1", "~4 c #49BFEF", "{4 c #4ABBEB", "]4 c #4BB7EB", "^4 c #53BCED", "/4 c #56BFEB", "(4 c #48ADE7", "_4 c #47A5E1", ":4 c #4DA9DE", "<4 c #4EA7DF", "[4 c #4CA4DE", "}4 c #4DA2DC", "|4 c #4EA1DA", "14 c #4B9ED8", "24 c #4D9CD5", "34 c #4F9BD6", "44 c #4F9DDB", "54 c #4D9AE2", "64 c #489EEA", "74 c #4CBAF6", "84 c #A4EEFE", "94 c #EFFEFF", "04 c #8CD6F9", "a4 c #3C99D9", "b4 c #4289C2", "c4 c #458FC5", "d4 c #448EC4", "e4 c #4189BC", "f4 c #3E84B8", "g4 c #3889C3", "h4 c #5DBEE9", "i4 c #ABFAFF", "j4 c #8CD5EF", "k4 c #3990C7", "l4 c #2F74A3", "m4 c #3378A6", "n4 c #2C70A2", "o4 c #296FA2", "p4 c #276EA1", "q4 c #276693", "r4 c #13619E", "s4 c #2E6DA5", "t4 c #888573", "u4 c #D2973F", "v4 c #F5A129", "w4 c #FEAD26", "x4 c #FEAB22", "y4 c #FEAA24", "z4 c #FEA422", "A4 c #FFA31F", "B4 c #FF9D1D", "C4 c #F88E1C", "D4 c #B06225", "E4 c #743C2D", "F4 c #7F432C", "G4 c #7D422B", "H4 c #00254C", "I4 c #065398", "J4 c #1776BF", "K4 c #227EBB", "L4 c #2080BE", "M4 c #2187C6", "N4 c #228DCB", "O4 c #2596D2", "P4 c #29A7DC", "Q4 c #2BADE0", "R4 c #2BACE2", "S4 c #2DB4E7", "T4 c #30BDEC", "U4 c #34C5F0", "V4 c #38CBF3", "W4 c #3CCFF6", "X4 c #48D3FA", "Y4 c #4FD5FC", "Z4 c #58D6FD", "`4 c #61D9FE", " 5 c #6CDAFD", ".5 c #76DBFE", "+5 c #7DDDFE", "@5 c #82DEFE", "#5 c #84DEFE", "$5 c #85DFFF", "%5 c #76DDFE", "&5 c #65D7FC", "*5 c #5DD7FB", "=5 c #57D5FA", "-5 c #53D3F9", ";5 c #4ED1F8", ">5 c #4DCEF7", ",5 c #4CCCF5", "'5 c #4CBEEE", ")5 c #45B8EE", "!5 c #52C4F3", "~5 c #8BEAFC", "{5 c #83F0FB", "]5 c #59D2F8", "^5 c #3FA7EC", "/5 c #3A9EE2", "(5 c #459FDD", "_5 c #4FA2DD", ":5 c #51A4DF", "<5 c #4FA1DD", "[5 c #4E9FDA", "}5 c #4E9ED9", "|5 c #4F9BDA", "15 c #51A3E5", "25 c #50B7F5", "35 c #53D2FC", "45 c #79ECFF", "55 c #D5FEFF", "65 c #F8FEFF", "75 c #94DBFA", "85 c #409EDD", "95 c #428AC4", "05 c #448DC3", "a5 c #448CC2", "b5 c #428ABE", "c5 c #4186BA", "d5 c #3882BE", "e5 c #45A6DF", "f5 c #9EF4FF", "g5 c #A3ECF7", "h5 c #4297CC", "i5 c #2C76AF", "j5 c #3377A9", "k5 c #3173A4", "l5 c #3582B3", "m5 c #2D75A5", "n5 c #2E79A7", "o5 c #3078A2", "p5 c #1E6498", "q5 c #1A6BAF", "r5 c #618590", "s5 c #BA9E54", "t5 c #EDA631", "u5 c #FDAE26", "v5 c #FFB526", "w5 c #FFB827", "x5 c #FEB327", "y5 c #FD9C1E", "z5 c #FD941A", "A5 c #AE5829", "B5 c #702E31", "C5 c #7E472B", "D5 c #001227", "E5 c #00366C", "F5 c #0C66B0", "G5 c #1F7EBF", "H5 c #217CB8", "I5 c #2081BE", "J5 c #2288C5", "K5 c #258FCB", "L5 c #299FD5", "M5 c #2BA9DD", "N5 c #2AA9DE", "O5 c #2CACE1", "P5 c #2EB4E6", "Q5 c #30BCEA", "R5 c #34C3EF", "S5 c #38C9F2", "T5 c #3ACDF5", "U5 c #3FD0F7", "V5 c #46D1F9", "W5 c #4CD3FB", "X5 c #53D5FC", "Y5 c #5BD7FD", "Z5 c #64D9FD", "`5 c #6CD9FD", " 6 c #71DBFD", ".6 c #74DCFE", "+6 c #79DCFE", "@6 c #7ADEFF", "#6 c #6DDAFE", "$6 c #66D8FC", "%6 c #5ED6FC", "&6 c #59D6FB", "*6 c #55D3FA", "=6 c #51D2F9", "-6 c #4ED2F8", ";6 c #4ECFF7", ">6 c #4CCDF6", ",6 c #4CCCF4", "'6 c #4BC6F1", ")6 c #46BEF0", "!6 c #3BB9F1", "~6 c #3EC1F6", "{6 c #62DFFB", "]6 c #71E5FE", "^6 c #6AD9FB", "/6 c #79F2FF", "(6 c #88E6FC", "_6 c #77CCF5", ":6 c #4DAFEC", "<6 c #3F9DE3", "[6 c #4B9EDC", "}6 c #509EDA", "|6 c #50A0DB", "16 c #4D9FE2", "26 c #57B9F6", "36 c #88E8FF", "46 c #B4FBFF", "56 c #CDFFFF", "66 c #F9FFFF", "76 c #99E0FA", "86 c #3F9FDC", "96 c #428AC6", "06 c #468EC3", "a6 c #438CC2", "b6 c #438CC1", "c6 c #3C84BC", "d6 c #3C92CE", "e6 c #7CD0F3", "f6 c #ABF6FE", "g6 c #64BDE1", "h6 c #2E7FB8", "i6 c #3275A8", "j6 c #3274A5", "k6 c #3480B5", "l6 c #2E75A7", "m6 c #296D9D", "n6 c #307DA9", "o6 c #2E79A5", "p6 c #1365A6", "q6 c #3F7DA2", "r6 c #9B9869", "s6 c #DFA037", "t6 c #FBA726", "u6 c #FFB626", "v6 c #FFB927", "w6 c #FEB226", "x6 c #FEA320", "y6 c #FFA320", "z6 c #FDA121", "A6 c #EA881B", "B6 c #E68218", "C6 c #EF891B", "D6 c #AC5829", "E6 c #702D32", "F6 c #7E3A2F", "G6 c #7C372F", "H6 c #001D3C", "I6 c #034788", "J6 c #1474BD", "K6 c #2383BD", "L6 c #237DB7", "M6 c #2381BC", "N6 c #2488C3", "O6 c #258FC9", "P6 c #279BD2", "Q6 c #28A2D8", "R6 c #2AA5DC", "S6 c #2DACDF", "T6 c #2FB4E4", "U6 c #31BCE9", "V6 c #33C2ED", "W6 c #36C7F1", "X6 c #3ACBF4", "Y6 c #3ECEF6", "Z6 c #44D1F8", "`6 c #48D3FB", " 7 c #4DD3FC", ".7 c #5AD6FC", "+7 c #60D8FD", "@7 c #65D9FD", "#7 c #68D9FE", "$7 c #68D9FD", "%7 c #63D8FC", "&7 c #5DD7FC", "*7 c #59D5FB", "=7 c #55D4FA", "-7 c #51D4FA", ";7 c #4FD2F9", ">7 c #4ED2F7", ",7 c #4FD1F8", "'7 c #4DCCF5", ")7 c #4DC9F4", "!7 c #4AC7F6", "~7 c #49C8F7", "{7 c #6CD8FB", "]7 c #A0E9FE", "^7 c #C5FAFF", "/7 c #90E4FD", "(7 c #4ABFF9", "_7 c #69D4FA", ":7 c #94EDFE", "<7 c #A3EEFF", "[7 c #9FE9FD", "}7 c #73C7F4", "|7 c #41A6EA", "17 c #4DA0E2", "27 c #549FDC", "37 c #4E9ADD", "47 c #50ABF0", "57 c #7BD9FF", "67 c #D7FEFE", "77 c #FAFFFD", "87 c #FCFFFE", "97 c #FFFFFF", "07 c #DAFDFF", "a7 c #7BDBFB", "b7 c #469EE4", "c7 c #4891CF", "d7 c #4793C8", "e7 c #448DC5", "f7 c #428ABF", "g7 c #3481BD", "h7 c #56A6DE", "i7 c #A8F0FF", "j7 c #83D4ED", "k7 c #3184BB", "l7 c #2F74A8", "m7 c #3376A7", "n7 c #3175A7", "o7 c #327AAE", "p7 c #3077A8", "q7 c #2B709F", "r7 c #2971A0", "s7 c #276797", "t7 c #1965A0", "u7 c #2674AE", "v7 c #7A8A7F", "w7 c #CB9C47", "x7 c #F39E2A", "y7 c #FEAF26", "z7 c #FEAF25", "A7 c #FDA925", "B7 c #FFA823", "C7 c #F99D21", "D7 c #DF861E", "E7 c #CF7619", "F7 c #DB7D1A", "G7 c #EA871C", "H7 c #B05F29", "I7 c #7A322F", "J7 c #792D30", "K7 c #002954", "L7 c #07539C", "M7 c #1B76B9", "N7 c #257EB5", "O7 c #227BB5", "P7 c #2487C3", "Q7 c #2691CA", "R7 c #299CD2", "S7 c #2AA0D6", "T7 c #2DABDE", "U7 c #2FB3E1", "V7 c #32BBE7", "W7 c #34C1EC", "X7 c #36C6F0", "Y7 c #3ACAF2", "Z7 c #41D0F7", "`7 c #45D2F9", " 8 c #47D3FC", ".8 c #4CD4FC", "+8 c #54D5FB", "@8 c #58D6FC", "#8 c #5BD6FD", "$8 c #5ED6FD", "%8 c #5FD7FC", "&8 c #5DD6FC", "*8 c #57D4FB", "=8 c #51D3FA", "-8 c #4ED3F9", ";8 c #4ECEF7", ">8 c #4DCBF4", ",8 c #4EC9F5", "'8 c #5AD5FD", ")8 c #82EEFF", "!8 c #A3FBFF", "~8 c #F7FFFF", "{8 c #A2F1FF", "]8 c #4FC5FA", "^8 c #4EAFEF", "/8 c #5EBBEF", "(8 c #6CC6F7", "_8 c #B0F3FE", ":8 c #9BDCFB", "<8 c #62BEF6", "[8 c #52ACEF", "}8 c #51ABF0", "|8 c #50BCFB", "18 c #A5ECFF", "28 c #FBFFFE", "38 c #FCFDFD", "48 c #FBFEFF", "58 c #D9FFFF", "68 c #9BFAFF", "78 c #66D2FE", "88 c #55ABF2", "98 c #4F9DDA", "08 c #4B96CD", "a8 c #4893CA", "b8 c #4692C8", "c8 c #4892CA", "d8 c #408BC0", "e8 c #2D80C1", "f8 c #68B4E6", "g8 c #C4FBFF", "h8 c #82CDEB", "i8 c #2E82BB", "j8 c #3479A8", "k8 c #337EAD", "l8 c #327DAC", "m8 c #2A6E9D", "n8 c #2A72A2", "o8 c #276C9B", "p8 c #206699", "q8 c #196AAD", "r8 c #598091", "s8 c #B49759", "t8 c #EA9C31", "u8 c #FDB029", "v8 c #FFB828", "w8 c #FDA526", "x8 c #FD9A22", "y8 c #FFA824", "z8 c #F29520", "A8 c #D57D1D", "B8 c #D67D1E", "C8 c #F59920", "D8 c #B1672A", "E8 c #702C2F", "F8 c #7E382C", "G8 c #7D3A2B", "H8 c #01396E", "I8 c #0D64AE", "J8 c #2177B5", "K8 c #2376AF", "L8 c #227CB7", "M8 c #2484BF", "N8 c #2586C2", "O8 c #2891CA", "P8 c #2DA2D3", "Q8 c #2CA1D5", "R8 c #2AA0D7", "S8 c #2DAADD", "T8 c #2FB3E2", "U8 c #33BBE7", "V8 c #34C0EA", "W8 c #35C2EC", "X8 c #38C7F0", "Y8 c #3BCBF3", "Z8 c #3FCEF4", "`8 c #41D0F6", " 9 c #44D2F9", ".9 c #48D2FB", "+9 c #4ED4FB", "@9 c #52D5FC", "#9 c #54D4FC", "$9 c #55D4FC", "%9 c #55D4FB", "&9 c #55D5FB", "*9 c #54D4FB", "=9 c #53D3FB", "-9 c #50D2FA", ";9 c #4ED2F9", ">9 c #4DD0F8", ",9 c #4DCDF7", "'9 c #4DCBF6", ")9 c #4EC9F4", "!9 c #4EC8F6", "~9 c #6EE5FE", "{9 c #82ECFD", "]9 c #71DAFC", "^9 c #9BF0FF", "/9 c #91E0FD", "(9 c #63C9F7", "_9 c #56BEF4", ":9 c #50AEEC", "<9 c #50ADEA", "[9 c #4BAAEC", "}9 c #63BEF6", "|9 c #C3F3FF", "19 c #D2FAFF", "29 c #68CEFF", "39 c #4DBCFE", "49 c #6DD5FE", "59 c #A1EAFF", "69 c #EBFCFF", "79 c #FFFEFF", "89 c #FAFCFE", "99 c #EBFFFE", "09 c #A4FFFF", "a9 c #6AF1FF", "b9 c #5CC9FF", "c9 c #5CB6F8", "d9 c #54A5E3", "e9 c #458CCE", "f9 c #4188C7", "g9 c #4891CA", "h9 c #4993CC", "i9 c #3A8ACF", "j9 c #4DA6E1", "k9 c #B3ECFB", "l9 c #BFF7FF", "m9 c #57B1E1", "n9 c #2F7FB8", "o9 c #367CAE", "p9 c #3579AA", "q9 c #3276A8", "r9 c #3683B1", "s9 c #3582AF", "t9 c #2B6D9E", "u9 c #307EAE", "v9 c #246390", "w9 c #1564A5", "x9 c #3F7CA4", "y9 c #9B926B", "z9 c #DEA53A", "A9 c #FBB52B", "B9 c #FFB226", "C9 c #FFB429", "D9 c #FEAD25", "E9 c #E8821C", "F9 c #EF891F", "G9 c #F99F20", "H9 c #B05F27", "I9 c #6B2533", "J9 c #752932", "K9 c #732A30", "L9 c #001C39", "M9 c #034685", "N9 c #1371B9", "O9 c #2277B1", "P9 c #2374AB", "Q9 c #2481BA", "R9 c #2687BF", "S9 c #2990C7", "T9 c #2C9DD0", "U9 c #2CA0D4", "V9 c #2BA1D5", "W9 c #2EA9DB", "X9 c #30B2E1", "Y9 c #33BAE6", "Z9 c #35BCE8", "`9 c #37BFEA", " 0 c #38C4EE", ".0 c #3AC8F1", "+0 c #3BCBF4", "@0 c #3ECDF5", "#0 c #41CEF6", "$0 c #45CFF8", "%0 c #47D1F9", "&0 c #4CD5FA", "*0 c #4DD3FB", "=0 c #4DD3F9", "-0 c #4ED3FA", ";0 c #4FD3FA", ">0 c #4DD2F9", ",0 c #4DCFF7", "'0 c #4ECBF6", ")0 c #4DC9F5", "!0 c #4EC7F5", "~0 c #51CBF9", "{0 c #6DE8FF", "]0 c #60D4F9", "^0 c #4DBFF5", "/0 c #59C9FA", "(0 c #52C0F5", "_0 c #4DB4F0", ":0 c #55B5F0", "<0 c #55B4EF", "[0 c #54B0EC", "}0 c #4DA9E9", "|0 c #5EB7F2", "10 c #C2F2FF", "20 c #BDF8FF", "30 c #97F5FF", "40 c #ACF7FF", "50 c #D7FCFF", "60 c #FEFEFE", "70 c #F7FEFE", "80 c #D1FFFF", "90 c #9BF7FF", "00 c #69D4FF", "a0 c #4EBCFC", "b0 c #4CBBF6", "c0 c #4BB6ED", "d0 c #46AAE4", "e0 c #3797DB", "f0 c #2D8ED9", "g0 c #3EADEA", "h0 c #A4E7FB", "i0 c #E0FFFF", "j0 c #7FCDF4", "k0 c #3692D2", "l0 c #3984BA", "m0 c #3A81B2", "n0 c #357AAA", "o0 c #3377A8", "p0 c #3680B0", "q0 c #347EAD", "r0 c #2D6F9F", "s0 c #2E75A6", "t0 c #2F7DAE", "u0 c #2972A6", "v0 c #276793", "w0 c #186098", "x0 c #2A72A9", "y0 c #808C7B", "z0 c #CFA244", "A0 c #F5B42C", "B0 c #FFB729", "C0 c #FEB829", "D0 c #FEAC24", "E0 c #FEA222", "F0 c #FBA022", "G0 c #FB9E20", "H0 c #FDA522", "I0 c #F7941F", "J0 c #A84C29", "K0 c #6C1D34", "L0 c #792931", "M0 c #752731", "N0 c #00264B", "O0 c #065197", "P0 c #186EB3", "Q0 c #2371A7", "R0 c #2477AD", "S0 c #257FB6", "T0 c #2683BB", "U0 c #2887BF", "V0 c #2A91C5", "W0 c #2C9ACD", "X0 c #2B9DD1", "Y0 c #2DA0D2", "Z0 c #2EA6D9", "`0 c #31B6E3", " a c #33BAE5", ".a c #36BDE9", "+a c #38C0EC", "@a c #3AC5EE", "#a c #3CC8F1", "$a c #3DCAF3", "%a c #3FCBF5", "&a c #42CDF6", "*a c #43D1F5", "=a c #46D1F7", "-a c #49D1F8", ";a c #4AD1F8", ">a c #4BD1F8", ",a c #4BD0F8", "'a c #4CD1F8", ")a c #4DD1F7", "!a c #4CCFF7", "~a c #4FCEF8", "{a c #4ECBF5", "]a c #4FC8F5", "^a c #4FC6F5", "/a c #53C7F8", "(a c #63DBFE", "_a c #55C6F8", ":a c #50BCF3", "b c #42CCF5", ",b c #45CEF6", "'b c #45CEF7", ")b c #47CEF7", "!b c #49CEF7", "~b c #4ACFF7", "{b c #4ACEF7", "]b c #4BCEF7", "^b c #4CCDF7", "/b c #51D0F8", "(b c #50CEF7", "_b c #4FCAF5", ":b c #51C5F6", "c c #41C8F2", ",c c #42CBF4", "'c c #44CDF4", ")c c #46CCF5", "!c c #47CCF5", "~c c #48CDF6", "{c c #49CDF7", "]c c #4ACCF6", "^c c #4BCBF6", "/c c #4CCBF6", "(c c #4ECCF7", "_c c #4FCAF6", ":c c #4FC7F5", "d c #39B9E6", ",d c #3BBBE9", "'d c #3CBEEB", ")d c #3CC2ED", "!d c #3FC4EF", "~d c #40C4F0", "{d c #41C7F1", "]d c #42C9F2", "^d c #45CAF3", "/d c #48CBF4", "(d c #49CBF6", "_d c #4ACAF5", ":d c #4AC9F4", "e c #3AB7E7", ",e c #3DBCEB", "'e c #3DBDE9", ")e c #3CBFE9", "!e c #3FBFEC", "~e c #40C0ED", "{e c #40C4EE", "]e c #43C6EF", "^e c #44C6F1", "/e c #45C6F2", "(e c #48C7F2", "_e c #48C8F3", ":e c #49C7F3", "f c #36A4D6", ",f c #37A8D8", "'f c #36AADA", ")f c #38AFDF", "!f c #3FBCE8", "~f c #41C0EB", "{f c #3DBBE8", "]f c #3DBAE7", "^f c #3FBBEA", "/f c #40BEEB", "(f c #40C0EB", "_f c #43C1ED", ":f c #44C3EE", "g c #2E89BC", ",g c #308FC1", "'g c #3194C5", ")g c #3398CA", "!g c #359DD0", "~g c #36A2D4", "{g c #36A6D6", "]g c #3AACDE", "^g c #3FB6E6", "/g c #40B7E6", "(g c #3CB5E4", "_g c #3DB5E5", ":g c #3EB7E8", "h c #2F87BB", ",h c #2F87B9", "'h c #308BBD", ")h c #3292C4", "!h c #3597CA", "~h c #379BCE", "{h c #379ED1", "]h c #36A3D2", "^h c #38A6D7", "/h c #3AA8DA", "(h c #3BACDD", "_h c #3DAEE0", ":h c #3EB0E1", "i c #338FC2", ",i c #3594C7", "'i c #379ACC", ")i c #39A1D5", "!i c #3AA5D7", "~i c #3BA7D9", "{i c #3CA8DC", "]i c #3CACDF", "^i c #3EAFE1", "/i c #41B1E3", "(i c #42B3E6", "_i c #42B4E7", ":i c #44B6E8", "j c #3592C5", ",j c #3796C8", "'j c #399ED1", ")j c #3BA2D5", "!j c #3CA4D7", "~j c #3CA5DA", "{j c #3EA8DC", "]j c #3EAADD", "^j c #41ACDF", "/j c #42B1E3", "(j c #43B2E5", "_j c #43B1E6", ":j c #46B3E7", "k c #3EA2D7", ",k c #40A4D9", "'k c #41A7DB", ")k c #41A9DE", "!k c #43ADE1", "~k c #45AFE4", "{k c #47B0E4", "]k c #48B1E4", "^k c #49B2E6", "/k c #49B3E9", "(k c #4BB4EC", "_k c #4DB6ED", ":k c #50B5EF", "l c #4DB2EA", ",l c #4FB4EC", "'l c #51B3ED", ")l c #52B5F0", "!l c #53B4F0", "~l c #56B5F2", "{l c #57B7F3", "]l c #59B7F4", "^l c #5AB8F6", "/l c #5EB8F8", "(l c #5EB8FA", "_l c #62B9FC", ":l c #66BAFF", "m c #60B7FA", ",m c #61B8FA", "'m c #62B8FD", ")m c #64B9FF", "!m c #65BAFF", "~m c #66B7FF", "{m c #66B6FD", "]m c #68BAFF", "^m c #68C3FF", "/m c #75DAFF", "(m c #95FBFF", "_m c #BBFFFF", ":m c #BBFDFF", "n c #7CD9FF", ",n c #AAF4FF", "'n c #FCFFFF", ")n c #ABEEFF", "!n c #81DCFF", "~n c #65C4FD", "{n c #5CB0F7", "]n c #5BA9F3", "^n c #5FB0F4", "/n c #6BCCFE", "(n c #70E4FF", "_n c #99F7FF", ":n c #99EBFE", "o c #CCFAFF", ",o c #E0FCFF", "'o c #E1FFFF", ")o c #A6F1FF", "!o c #75D5FF", "~o c #5EBDFF", "{o c #60BAFF", "]o c #66CFFF", "^o c #90EFFF", "/o c #DFF9FF", "(o c #94F0FD", "_o c #64D6F9", ":o c #50A5E4", "p c #FBFFFF", ",p c #71DEFF", "'p c #64D3FF", ")p c #85E7FF", "!p c #D4FBFF", "~p c #DFF3FA", "{p c #74CDF2", "]p c #42B1EB", "^p c #4FA7E1", "/p c #4C94CD", "(p c #468CC4", "_p c #448CC3", ":p c #4189BD", "

Q c #1F6EAD", ",Q c #257AB4", "'Q c #2878B0", ")Q c #2771A9", "!Q c #256B9E", "~Q c #1F699F", "{Q c #2073A9", "]Q c #3588B7", "^Q c #58A4CB", "/Q c #58C0E8", "(Q c #5BE1FD", "_Q c #5DE0F8", ":Q c #58C6E8", "R c #000B19", ",R c #00172C", "'R c #001C37", ")R c #002344", "!R c #003469", "~R c #033A71", "{R c #305978", "]R c #798180", "^R c #747B7C", "/R c #767877", "(R c #817B72", "_R c #8A846D", ":R c #948C66", "S c #FD941F", ",S c #FFC828", "'S c #FFC729", ")S c #FFC320", "!S c #FFBC27", "~S c #FE9B1D", "{S c #FF9E21", "]S c #FB9020", "^S c #EC851D", "/S c #ED851C", "(S c #B36126", "_S c #67272E", ":S c #5D1F30", "T c #FD931E", ",T c #FD9A21", "'T c #FE981F", ")T c #F9A321", "!T c #B16C28", "~T c #753230", "{T c #6F2932", "]T c #74430C", "^T c #FEA119", "/T c #FFC11F", "(T c #FFC520", "_T c #FB911C", ":T c #FC981D", "U c #F9C126", ",U c #F9BE26", "'U c #F4AB1D", ")U c #AF7528", "!U c #72492E", "~U c #7F5728", "{U c #7D5428", "]U c #7F614D", "^U c #755A46", "/U c #4F3B2F", "(U c #4D3B2F", "_U c #4E3B2F", ":U c #70502B", "V c #72512C", ",V c #725929", "'V c #72562A", ")V c #724D2E", "!V c #72542B", "~V c #725F27", "{V c #725C29", "]V c #72572C", "^V c #725828", "/V c #725C28", "(V c #726226", "_V c #726126", ":V c #725D29", "W c #7C5F4A", ",W c #735A4A", "'W c #645238", ")W c #7D5523", "!W c #7B3F2F", "~W c #772E33", "{W c #7A412D", "]W c #7E512A", "^W c #7D4A2C", "/W c #7D4E2D", "(W c #7D492C", "_W c #7D532B", ":W c #7D5829", " , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 : 6 7 8 9 0 a b c d e f g h i j k l m n 5 o p q r s t u v w x ", " . . . y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ` X ...+. .@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^.]././.(._.:.<.[.}.|.1.2. ", " . . 3.4.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.s.v.w.x.y.z.A.B.C.D.E.F.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.w.U.V.W.X.Y.Z.`.} + ", " . y .+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@+#+$+%+&+*+=+-+;+>+,+'+)+=+!+~+{+]+^+/+(+_+:+<+[+}+|+1+2+3+4+5+6+/+7+8+9+0+a+b+c+4+d+e+f+g+h+i+4+j+k+l+m+:+j+n+o+p+q+r+s+t+ ", " . y .+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++u+v+w+x+y+z+A+B+C+D+E+F+G+H+I+n+J+K+L+M+N+O+P+Q+R+S+T+U+V+1+k+W+7+<+B+X+Y+Z+F+`+ @.@i++@@@H+#@B+$@%@&@R+*@=@-@;@>@,@'@)@!@~@ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++{@]@^@/@(@_@:@<@[@}@}@|@1@2@3@4@5@6@7@8@9@0@a@b@c@d@e@f@g@h@i@j@k@l@m@n@o@p@q@m@r@3@h@s@t@u@v@w@x@y@z@A@z@B@C@D@E@F@G@H@I@J@ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++u+K@L@M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$###D@%#&#r@*#=#-#j@;#>#,#k@'#)#!#~#{#]#^#^#A@/#(#_#:#y@4@<#x@!#_+[#}#|#1#2#3# ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++4#5#6#A@7#8#;#9#0#a#b#c#d#e#f#g#h#i#6@j#k#l#5@m#n#o#z@p#q#>#i@r#[@s#t#u#v#%#w#g@x#y#z#A#B#C#D#E#F#G#0@H#I#J#K#L#M#N#O#P#Q#R# ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++S#T#U#&@V#>#W#[@X#Y#Z#`# $.$+$J+@$#$y@$$%$&$*$=$-$$#;$%#>$x#,$g@,#q#'$&#C@)$!$x#{#~${$E#]$^$/$($>@_$I#Z@:$<$[$}$A+|$1$2$3$4$ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++5$6$7$8$9$w#>#0$a$b$c$d$e$f$g$h$i$j$k$l$m$'#n$o$p$q$A#Z@G#r$A@s$t$r@u$t#@@4+j#t$v$w$x$y$z$A$B$C$D$E$F$P+G$<#7@H$I$J$K$L$M$N$ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++O$P$b@Q$R$i+S$T$U$V$W$X$Y$Z$`$ %.%+%@%#%$%%%&%*%=%-%;%>%,%c@o$>%*$L#'%)%!%~%3@Z@{%]%x$^%/%(%_%:%<%[%}%|%1%2%)$h+3%c#4%5%6%7% ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++8%9%0%a%Z@q$b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q%r%s%t%u%v%w%x%y%q$z%A%B%<@C%D%E%F%G%H%I%E#J%K%L%M%N%O%P%Q%R%S%T%U%5+N@V%W%X%Y%Z% ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++`% &.&+&@&#&$&%&&&*&=&-&;&>&,&'&)&!&~&{&]&^&/&(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&G%0&z%a&b&c&d&e&[%*%9&9&f&g&h&i&j&k&l&m&n&o&/$p&L#>+q&r&s&t&u& ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++v&w&x&y&z&A&B&C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W&X&Y&Z&`& *.*+*@*#*3+$*%*&***l$w%=*-*;*>*,*0%'*J%$#)*!*~*{*]*^*/*_%(*_*:*|%<*y#A+[*}*G |*1* ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2*3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*A*3@B*C*D*E*F*G*{#q@i+H*I*3@J*K*3+T%G%>@L*M**%n&P%L%N*O*P*Q*|%I%F$%*x@R*S*T*U*V*W* ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2*X*Y*5*Z*`* =.=+=@=#=$=%=&=*===-=;=>=,='=)=!=~={=]=^=/=(=_=:=<=[=}=|=1=2=3=4=5=6=7=8=9=0=a=r$J#<+M#L@2+i+b=%*7&c==*5&d=w%e={*f=g=h=Q%l$&#i=C@j=4@;@k=l=m=n=o= ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2*p=q=r=s= =t=u=v=w=x=y=z=A=B=C=D=E=F=G=H=I=J=K=L=M=N=O=P=Q=R=S=T=U=V=W=X=Y=Z=`= -.-+-@-G%*@r$5@#-$-I#4@)$I#%-R*&-*-*-0%P+8&=---A$;->-,-'-$@)-!-~-E#I#}+{-]-^-/-(- ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++_-@&:-<-[-}-|-1-2-3-4-5-6-7-8-9-0-a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-A-N#B-C-J%##D-E-F-H*4@i+l$/#G*G-<*A#H-A#I-J---/%/%g&K-A$L-M-N-O-E#j={%P-Q-R-S-T- ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2*@&U-V-W-X-Y-Z-`- ;.;+;@;#;$;%;&;*;=;-;;;>;,;';);!;~;{;];^;/;(;_;:;<;[;};|;1;2;3;4;5;6;7;8;9;0;a;b;c;H#:#d;e;h#+@f;g;%$F*h;j=j=p&i;p$j;k;l;-%m;n;o;p;q;q$y$_$H%r;s;t;u;v; ", " . y 5.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&w;x;y;z;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;Y;Z;`; >.>+>@>#>$>%>&>*>=>->;>>>,>'>)>!>~>{>*#]>c;^>0=/>(>_>:><>[>}>a=:$|>i#1>[%5&J-2>2>p$q$M*3>I-]$E#4>5>6>7>8>9> ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++v&0>a>b>c>d>e>f>g>h>i>j>k>l>m>n>o>p>q>r>s>t>u>v>w>x>y>z>A>B>C>D>E>F>G>H>I>J>K>L>M>N>O>P>&>Q>R>S>T>U>V>W>X>Y>Z>j#C+`> ,.,+,h%@,p@y@:$)$#,#,)*J-5&1>I-H%J-8&$,1>>@%,&,*,=,-,;,>,,, ", " . y 5.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++&',),!,~,{,],^,/,(,_,:,<,[,},|,1,2,3,4,5,6,7,8,9,0,a,b,c,d,e,f,g,h,i,i-j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,_>F,G,H,:>)#!#I,}>7@Z@J,c@&-8&5&3>K%n;K%L-K,0%9&0%L,M,N,O,P,Q, ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++R,S,T,U,V,W,X,Y,Z,`, '.'+'@'#'$'%'&'*'='-';'>',''')'!'~'{']'^'/'('_':'<'['i-}'|'1'2'3'4'5'6'&>7'8'9'0'a'b'c'd'e'f'g'h'i'j'k'l'm'u#k@h@h#n'o'p'7@;@q'o&n&r':%h&C$K,J#s't'u'v'w'x'y'z' ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++`%#&A'B'C'D'E'F'G'H'I'J'K'L'M'N'O'P'Q'R'S'T'U'V'W'X'Y'Z'`' ).)+)@)#)$)%)&)*)=)-);)>),)')))!)~){)])^)/)()_):)<)[)})|)1)2)3)4)5)6)7)8)9)a+Y@Z@Y@0)f@4@a)q$--b)c)d)l&e)I-+#f)g)h)i)j)k)l)m) ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++ &n)o)p)q)r)s)t)u)v)w)x)y)z)A)B)C)D)E)F)G)H)I)J)K)L)M)N)O)P)Q)R)S)T)U)V)W)X)Y)Z)`) !.!+!@!#!$!%!&!*!=!-!;!>!P>,!'!)!!!~!{!]!^!/!(!_!:!r@~;-,~'~1!)~!~2@~~{~]~^~/~(~_~:~ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++2*w;<~[~}~|~1~2~3~4~5~6~7~8~9~0~a~b~c~d~e~f~g~h~i~j~k~l~m~n~o~p~q~!'r~s~t~u~v~w~x~y~z~A~B~C~D~E~F~G~H~I~J~K~L~M~~)N~O~P~Q~R~S~T~U~V~W~X~Y~Z~U+L+`~ {H#h#J#:#.{'*+{@{#{:%${%{b#&{*{K+={-{;{>{,{ ", " . y 5.++++++++++++++++++++++++++++++++++++++++++'{0!){!{~{{{]{^{/{({_{:{<{[{}{|{|{1{2{3{4{5{6{7{8{9{0{a{b{c{d{e{f{g{h{i{j{k{l{m{n{o{p{q{r{s{t{u{v{w{x{y{z{A{B{C{K~{)Z!D{E{F{G{H{I{J{K{L{M{N{O{P{Q{-~v#R{g@x#S{T{l;U{V{W{v$j+g%X{Y{&$Z{`{ ].]+]@] ", " . y 5.++++++++++++++++++++++++++++++++++++++++`%#]$]%]&]*]=]-];]4~>],]'])]!]~]{]]]^]/](]_]:]<][]}]|]1]2]3]4]5]6]7]8]9]0]a]T)b]m{c]d]e]f]g]h]i]j]k]l]m]n]o]p]q]r]s]t]K~u]v]w]x]y]z]A]x,B]C]D]E]F]G]H]I]-~'#Q@i@J]n&K]L]g@f#M]k@N]O]:$5=P]Q]R]S]T] ", " . y 5.++++++++++++++++++++++++++++++++++++++2*#&U]V]W]X]Y]Z];]`] ^.^+^@^#^$^%^&^*^=^-^;^>^,^'^)^!^~^{^]^^^/^(^_^:^<^[^}^|^1^2^3^4^5^6^7^8^9^0^a^b^c^d^e^f^g^y{h^i^j^k^l^m^n^o^p^z]q^r^J{s^t^u^v^w^;#x^D@I,3+y^z^k&A^B^C^6=u$q@D^**b;j+&+E^F^G^Y% ", " . y 5.++++++++++++++++++++++++++++++++++++++H^I^J^K^L^M^N^O^P^Q^R^S^T^U^%^V^W^X^Y^Z^`^`^`^ /./+/@/#/$/%/&/*/=/-/;/>/,/'/)/!/~/{/]/^///(/_/:/d/e/f/g/h/i/j/@-^%9&1>k/'~l/m/L#n/o/H$p/q/r/s/t/u/v/w/x/y/ ", " . y 5.++++++++++++++++++++++++++++++++++++.&z/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/T/U/V/W/X/Y/Z/@/`/ (.(+(@(#($(%(&(*(=(-(;(>(,(//'()(!(~({(](Z;^(/(((_(:(<([(}(|(1(2(3(4(5(^)6(7(8(9(0(a(b(c(d(e(|%[%f(l&@{&*g(h(i(j(k(l(m(n(o(p(q(r(s(t(u( ", " . y 5.++++++++++++++++++++++++++++++++++`%4*v(w(x(y(z(A(B(C(D(E(F(G(H(I(J(K(L(M(N(O(P(Q(R(S(T(U(V(W(X(Y(Z(`( _._+_@_#_$_%_&_*_=_-_;_>_,_'_)_!_~_{_]_^_/_(___:_<_[_}_|_1_2_3_4_5_6_;![;7_8_9_0_a_b_c_d_J%~*a)N-e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_ ", " . y 5.++++++++++++++++++++++++++++++++++R,x;v_w_x_y_z_A_B_C_D_E_F_G_H_I_J_K_N(L_M_N_O_P_Q_R_S_T_U_V_W_X_Y_Z_`_ :.:+:@:#:$:%:&:*:=:-:;:>:,:':):!:~:{:]:I=^:/:(:_:::<:o][:}:|:1:2:3:4(4:5:6:7:8:9:0:a:b:c:l;d:e:f:g:h:B+l(i:j:k:l:m:n:o:p:q:r:s:t: ", " . y 5.++++++++++++++++++++++++++++++++u:v:W-w:x:y:z:A:B:C:D:E:T^F:G:H:I:J:K:L:M:N:O:P:Q:R:S:T:U:V:W:X:Y:Z:`: <.<+<@<#<$<%<&<*<=<-<;<><,<'<)[,['[)[![~[{[][^[/[([_[:[<[[[}[|[1[2[3[4[5[6[f^7[8[9[0[a[b[c[d[e[f[g[h[i[j[k[l[<@m[!%n[o[p[q[r[s[t[u[v[w[x[y[z[A[B[C[ ", " . y 5.++++++++++++++++++++++++++++++w&D[E[F[G[H[I[J[K[L[M[N[O[P[Q[R[S[U/T[U[R:S},}'})}!}~}{}]}^}/}(}_}:}<}[}}}|}1}2}3}4}5[5}6}7}8}9}0}a}b}c}d}e}f}g}h}i}j}k}o/%#`~l}m}n}o}p}q}r}s}t}u}v}w}x}y}z}A} ", " . y 5.++++++++++++++++++++++++++++++0!B}C}D}E}F}G}H}I}J}K}L}M}N}O}P}Q}R}S}Q|,|'|)|!|~|{|]|^|/|(|_|:|<|[|}|||1|2|3|4|5|6|7|8|9|0|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|u$r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G| ", " . y 5.++++++++++++++++++++++++++++.&H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|`|W< 1.1+1@1#1$1V[%1&1*1=1-1;1>1,1&|'1)1!1~1{1]1^1/1(1_1:1<1[1}1|111213141516171819101a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1r1s1t1u1v1w1`>x1y1z1n[A1B1C1D1E1F1G1H1I1J1K1L1 ", " . y 5.++++++++++++++++++++++++++`%0!M1N1O1P1Q1R1S1T1U1V1W1X1Y1Z1`1 2.2+2@2`|%1 1#2$2%2&2*2=2-2&1Z<=1;2#|>2,2'2)2!2~1~2{2]2^2/2(2_2:2<2[2}2|21222324252627281829202a2b2c2d2e2f2g2h2i2j23'k2l2m27'n2o2p2q2r2s2t2u2v2x1@,w2x2s}v[y2z2A2B2C2D2E2F2G2 ", " . y 5.++++++++++++++++++++++++++.&H2I2J2K2L2M2N2O2P2Q2R2S2T2U2V2W2 2Q}X2Y2Z2`2 3.3+3@3#3$3%3&3*3=3-3;3#|>3,3'3)3!3~3{3]3^3/3(3_3:3<3[3}3|31323233343536373`)839303a3b3c3d3e3f3i1g3h3i3j3k3l3m3n3o3p3[)q3r3s3t3u3v3h%m@w3x3y3z3A3B3!+s#C3D3E3F3G3 ", " . y 5.++++++++++++++++++++++++++#]H3I3J3K3L3M3N3O3P3Q3R3S3T3U3V3W3X3Y3Z3`3 4.4+4@4W[Y[#4$4%4&4*4=4-4;4>4>3,4'4)4!4~4{4]4^4/4(4_4:4<4[4}4|414243444546474849404a4b4c4d4e4f4g4h4i4j4k4*!G~l4m40/n4o4p4q4r4s4t4u4v4w4r|8)x4y4z4A4u$c+~+B4C4D4E4F4G4 ", " . y 5.++++++++++++++++++++++++ &a>H4I4J4K4L4M4N4O4P4Q4R4S4T4U4V4W4*^X4Y4Z4`4 5.5+5@5#5$5-2%5Z2&5*5=5-5;5>3>5,5)4!4'5)5!5~5{5]5^5/5(5_5:5<5[5}5|515253545556575859505a5b5c5d5e5f5g5h5i5j5k5g^l5m5n2n5o5p5q5r5s5t5u5v5w5y#x5k@2@A4d:y5z5b#A5B5l C5 ", " . y 5.++++++++++++++++++++++++R,D5E5F5G5H5I5J5K5L5M5N5O5P5Q5R5S5T5U5V5W5X5Y5Z5`5 6.6+6@6&4#6$6%6&6*6=6-6;6>6,6'6)6!6~6{6]6^6/6(6_6:6<6[6}6|6}61626364656666576869606a6b6b5c6d6e6f6g6h6i6j61:k6l6m6n6o6%>p6q6r6s6t6u6v6p@w6<>x6y6z6A6B6C6D6E6F6G6 ", " . y 5.++++++++++++++++++++++`%y&H6I6J6K6L6M6N6O6P6Q6R6S6T6U6V6W6X6Y6Z6`6 7X5.7+7@7#7 5#6$7%7&7*7=7-7;7>7,7'7)7!7~7{7]7^7/7(7_7:7<7[7}7|717273747576777879707a7b7c7d7e7a605f7g7h7i7j7k7l7m7n7o7p7q7r7u,s7t7u7v7w7x7y7g;z7+,A7B7C7D7E7F7G7H7~ I7J7 ", " . y 5.++++++++++++++++++++++ &I^K7L7M7N7O7M6P7Q7R7S7%'T7U7V7W7X7Y7_]Z7`7 8.8+8@8#8$8%8`<&8.7*8;4=8-8;5>3;8>8,8'8)8!8a^~8{8]8^8/8(8Y[_8:8<8[8}8|818283848586878889808a8b8c8d8e8f8g8h8i82(j8G~k8l8m8>!n8o8p8q8r8s8t8u8v8r|w8x8y8z8A8B8t}C8D8E8F8G8 ", " . y 5.++++++++++++++++++++++H^){H8I8J8K8L8M8N8O8P8Q8R8S8T8U8V8W8X8Y8Z8`8 9.9+9@9#9$9%9&9*9=9=8-9;9>9>5,9'9)9!9~9{9]9^9/9(9_9:9<9[9}9|919293949596979899909a9b9c9d9e9f9g9h9i9j9k9l9m9n9o9p9q9r9s9t9m5u97'v9w9x9y9z9A9B9C9D9x1z4v[E9F9z2G9H9I9J9K9 ", " . y 5.++++++++++++++++++++++4*L9M9N9O9P9Q9#;R9S9T9U9V9W9X9Y9Z9`9 0.0+0@0#0$0%0&0*0=0-0;0-0;7>0-8.},0,9'0)0!0~0{0]0^0/0(0_0:0<0[0}0|010Z;20{8304050976070809000a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0A0B0C0D0E0r}F0G0H0k$I0J0K0L0M0 ", " . y 5.++++++++++++++++++++2*v:N0O0P0Q0R0S0T0U0V0W0X0Y0Z0T'`0 a.a+a@a#a$a%a&a*a=a-a;a>a,a,a'a'a)a!a;6~a{a]a^a/a(a_a:aKaLaMaNaOa ", " . y 5.++++++++++++++++++++.&PaQaRaSaTaUaVaWaXaYaZa`a b.b+b@b#b$b%b&b*b=b-b;b>b,b,b'b)b!b~b{b]b^b^b/b(b_b^a:bc,c'c)c!c~c{c]c^c^c/c(c_c:cM1VcWcXcYcZc`c d.d+d@d#d$d%d&d*d=d-d;d>d,d'd)d!d~d{d]d]d^d/d(d_d:dIdJdKdLdMdNd`>j@Od`>Pdj@QdS*RdSdTdUd ", " . y 5.++++++++++++++++++++w;VdWdXdn-YdZd`d e.e+e@e#e$e%e&e*e=e-e;e>e,e'e)e!e~e{e]e^e/e(e_e:ef,f'f)f!f~f{f]f^f/f(f_f:fPfQfRfSfTfUfVfh@t$h@Wf>#k+XfYfZf`f g ", " . y 5.++++++++++++++++++`%.g+g@g#g$g%g&g*g=g-g;g>g,g'g)g!g~g{g,f]g^g/g(g_g:gh,h'h)h!h~h{h]h^h/h(h_h:hQhRhShThUhVhWhA@!~<#I,O]2+XhYhZh`h i ", " . y 5.++++++++++++++++++u:.i+i@i#i.~$i%i&ip^*i=i-i;i>i,it~'i{h)i!i~i{i]i^i/i(i_i:iNiOiPiQiRiSif_K#h;z@Ti_+I,Z{UiViWiXiYi ", " . y 5.++++++++++++++++++u:x;Zi`i j.j+j@j#j$j%j&j*j=j-j;j>j,jT)'j)j!j~j{j]j^j/j(j_j:jk,k'k)k!k~k{k]k^k/k(k_k:kl,l'l)l!l~l{l]l^lef/l(l4k_l6k8k:l8k(PlQlRlSlTlUlVlWlXlYlZl`l m.m+m@m#m$m%m&m*m=m-m;m>m,m'm)m!m:l~m{m{m]m^m/m(m_m:m$x4k@W+smtmumvmwm ", " . y 5.++++++++++++++++++u:xmymzmAmBmu,7(CmDmEmFmGmHmImJmJmKmLmMm^/NmOmPmQmRmSm_1TmUmVmWmXmYmZm`m n.n+nad@n#n$n%n&n*nfj:l=n~m-n-n;n>n,nI=~8'n07)n!n~n{n]n^n/n(n_npkba:no,o66'o)o!o~o{o]o^o`)/o(o_o:opY;,p'p)p!p~p{p]p^p/p(pCi_pf7:p3oq,q'q)q!q~q{q]q^q/q(qBf_q052n:p:qp*r=r-r;r>r,r'r)r!r~r{r2}]rvk^r/rDejl(r_r:rs,s's)s!s~s{s]s^s/s(s_s:st,t't)t!t~t{t9q]t^tS@9+_#/t(t_t:t#u$u%u&u*u=u-u;u_@>u;$,u'u)u!u~u{u ", " . y 5.++++++++++++++++++++.&H2]u^u/u(ubn_uq74t:u@!yk1_<(v,v'vLi2p@!o05/)v!v~v{vKh]v^vDi/v(vyeEg_v:vUvVvWvXvYvZvwa`vLf wsawbBdra.w+wCe]vwc@w#w_[Bf$w%w&w*w=w-w;w>w,w'wyh)w!w~wcv{w]w`n^w3dkc/w(w_woupu:wx,x'xr{)x!x~x{x]x^x/x(x_x:xxxyxt]KiG~zx1y,y'y)y!y~ysp{yyx]y]y^yz ", " . y 5.++++++++++++++++++++++++w&V-,z'z)z!z~zL>{zw2z'w3z4z5z6z7z8z9z0zaz2wnentwhltAybzczdz}vezfzgzhzizjzC=,qjzkzlzmznzBeozpzqz<_rzx{7osztz]=wnuzNivzwzxzyzzzAzBzCzPv0)Dzo#$->#Ezh$FzGzHzIzJzRj ", " . y 5.++++++++++++++++++++++++`%KzLzMzNzybOzPzQzRzSzk^upNhTzo9UzVzd1b1@tWzb5b3_qamGxXzYzZz=wJx`z A.ADyBy+A@A#A$A%A}/&A*A=A+Avi-A;AXw>Apypy1z,Any'A)A!A~A{AI=19]A^A/A(A_A:Agllp=B-B;BPhjmybMf>B=!Fjh^Nh,B'B4[3})B^vb1!Bbm05~B{Bgy]BEg^B/B(B(B}z_B:Bp1B2B3B4B.AVwKxlyVw,ATw5B+s&wxe6B7B8B9B0BaBbBcBdBeBxcfB/zgB,Bz{hBiB5(o1u]$>_u8(jBkBlBmBnBoB0%D$pB-%i#0%qBp&fp%#rBsBtBuBvBwB ", " . y 5.++++++++++++++++++++++++++++#]xByBzBABBB.jyb>!CBrp:uDBTzVzraDe9|^rEfEBFB5|GBa6a5~r]BHBIB[z'AJB(BKB}zVwC,C}%$#z%'Ca@)C,#]>!C~C{C]C^C ", " . y 5.+++++++++++++++++++++++++++++&/C(C_C-v:CpbCcCdCeCfC/BSw^BgChCxeEgEgHxiCjCkClCmCnCoCJhpzpC/zqCrCsCtCuCvCwC5t2AxCr^;BLeyCzCACBCCCDCr$ECFCR*:#GCS$D@3+HCV+ICH7JCKCLC ", " . y 5.++++++++++++++++++++++++++++++MCNCOCPCQC&>HdQzm6RCLi4(SCTCUCD_zBfDf,D'D)D!D~D{DSA]D9|9|^Do]o]/D(D[Aa/{y_D;v,!Ph:D:Cn2[CNfDcgDhDiDjDkl,B<_Adtbc1kD!B#wlDmDnDoDpDqDrDsD6utDuDvDwDxDyD80zDADBDCDDDEDFDGDCfHDIDGxJD!rKDLDMDNDalODPDQDRDSDIihlTDx{UDVD-sPgyxA@D@g@<@&Eh+*E=E-E;E>E ", " . y 5.++++++++++++++++++++++++++++++++,E$]+i'E)E!E~E{E]E^El3rpDBU!/E6/(E_E:::E:#FE$-b@h;GEHEIEJEKELEMENE ", " . y 5.++++++++++++++++++++++++++++++++'{OEs=PEQERESETEUEVERzH{WEXEYE4/mA3/ZE`E9|dm F.F+F@F#F$F%Fhs&Fc8*F=F-F;F>F,F'F)F!F~F{F]F^F/F(F_F:F;~6@J,#,`@gFhFF-#,c@=*iFjFkFlFmF ", " . y 5.++++++++++++++++++++++++++++++++++w&nFoFpFc'qFSEszrFsF~ztFuFvFwFGen0<_5[xFxFyFzFAFBFCFDFEFFFGFHFIFJFKFLF>;MFNFOFPF[oQFRFSFTFUFzvVFWFXFYFZF`F G.G+G@G#Gxk$G%G5o&GEjq]H~*G=GFd-G;G>Gxa;v,G'G)G!G~G{G!+B4]Ga%5D3Dh#&-c@d;|>F-^GGCb%@v/G(G_G:G ", " . y 5.++++++++++++++++++++++++++++++++++`%#&$]}-opG{FGGGHGIGJGKGLGMGNG'+w#,#OGS@Fkx@J#[!}>}>~-rmPGQGRGSGTG( ", " . y 5.++++++++++++++++++++++++++++++++++++'{UGVGC'WGXGYGv,u,b/ZGs0`G5_Ogll-s5H,Hf7f7c3'Hbmb6}u)H!H~H{H-)_mCh]H^H/H}u(HDe_H[_:HI,I'I)I!I|H6(Nfwnvo~Ik3{IGe1:]I^I/I(I_I:I'n GvIwIJExIyIzIAI ", " . y 5.++++++++++++++++++++++++++++++++++++++++`%R,H2BICIDIEIYyFI()GIHI1HMf;sT!GmIIJIKILIMINIOIPIQIRISITIUIVIWIRDzdJHI,J'J)J!J~J{J]J^J/J(J_J:JK,K'Kc/3tGl)KwCxok^!K~K{K]K^K/K(K2<_KfI:K%s:KiK.vjKIakK=#lKmK.v}$i=nKL,X@oKpKqKX+rKsKtKuKvKI7wK ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++'{xKyKzKAKBKCK.jDKEKFK'vtFZGGKHKIKJKKKLKMKNKh^NgOKmADG<(PKQKRKSKTKUKVKWKXKYKZK`K L.L+L@L#L;J$LGe%L3(&L*L=L-L;Lm8>LzbqF,L'L)L!L~L{L]L^L/L(Lk+{#w@k#j#~#_L:L0+!q^[CGL,!4AHLILJLKLLLMLNLOLK,O+*$#$O-4=PL5=H-QLh#RLh;^>##B%D@~-'#e#SLTLULVLWLXLYLZL ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++H^`L M.M+M@M#MkA!E.j$M%M&M*M=M-M;M>M,M'M)MqqJf!M~M{M]M^M/M(M_M:M8M.j9M0MaMbMcMdMeMfMgMhMF-%,%@#-iM*@jMkMlMs%]$q$mM^G+B|>a@)$Y@nMoMpMqMC+rMsMtMuMWe ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++X*vM){wMxMyMzMREAMBMCMDMEMFMGMHMIM;!5(k2pq1:JMKMLMMM[}NMOM}[&rPMQMRMSMTMUMhbVMWMHJn#C-^$&N>@4&c@c;*N.#x$A#c@0@a=<#>%y$J]=N-NHC8#(L;N]->N} ,N ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++.&'NH|)N!N~N{N]N^N/N(N3d_N:NO/O@#5@#,]$(O$,A#i#b@B@|><*C-'*${G%c@h;%*_O:OLir8O_'9O0OaObOcOdO}NeOfOgOhOiOjOd-kOlOmOnOoOpOqOrOOfsOtOuOvOwOxOyOzOAOBOCODOd=2>|%EOFOGOw$:+d@HOB%/L|>#,$#IO Bb@p&Q+d=x%k;--##JOo#l+wIKOLOMONOEN ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++`%OOy&eJUvPOQOROSOTOUOVO;BWOXOYOZO`O P.P+P@PZv#P$P%P&P*P=P-P;P>P,P'P)P!P~P{P]P^P/P(P_P:P8Pi;9P0PaPbP*#G*cPdP]-ePfPkp ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++`%OO',U]gPYehPiPjPkPlPuxmPnPoPpPqPrPsPL>tPuPvPwPxPyPzPAPBPD=mbCPDPEPaFFPGPHPIPJPKPLPMPNPOP4>--,-'*8PG%a@^%PP9PQPRPo&SP/L%'CYPZP`Ps+ Q ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2*X*0!.Q+Q@Q#Q$Q%Q&Q*Q=Q-Q;Q>Q,Q'Q)Q7Oo4!Q~Q{Q]Q^Q/Q(Q_Q:QRa!,R'R)Rlp@h.M!RC'~R{R]R^R/R(R_R:RqB--v%o;<%3P/L^OzRL-/LH#R*I#)Cx@a=i#ARBRCRDRERb;cqKEFRGRHR ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2* &v&+&X*IRJRKRLRMRNRORPRQR$-F-T{RR&$9#SRTRZJW#<$Z@UR<*&-##c@C-R+>%0%F-c=2>p$VRWRXRv%i#+B;@y$$,J%<*%-**H]k#R{D@O-!$X@YRZR`Rs[n< S.S+S@S ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#S$S9r%S&SPG2+wI-@cP1>*S=S-S#z;S>S1@h#o#a=c@<#S$UQi;,S'S>@)*H%1>[%L%U{)SQ+:#@-G$=$M*$,h:!SO]j#x6~Sa+H])#-#{S]S^S/S)&(S_S:S!*m;d=aSURw@H$@Ear'#g@`>tIbScSdSeSfSgShSiSjS ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#SkSlS>+J+Y@^>o#G$}!%@mSZ{nSoSLcpSqS9#-~#$<#&*9RrS$,=%/$=%k;t%sS[%tSuSvSwSn&--pBxSp$ySv$G*]#}$zSAS&ES{t#fo0qBSCSDSES=EFSGSHS ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#SISJSKSLSH###)$*@0%hFy$G%o#e+foqm$I2D#$G#dHJ]H*J-5&wSMSNSOSz^t%e)PSr'QS<%pBf&RSNS*%*@|+A@w@q@=#<@SSWf[@TSUSVSr}d:WSXSYSZS' ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++`S T$E.T0@H#D@4&xN9&Q+'*]%+T@T#T1@HC<$;~GCTQA#|>$T.BNS{*e)%TP%NSQ*&T*TRP<%n;5&=T-T;Tm/:$#$J#h@g@}$!#OdB3>T,TbS'T @)T!TZf~T{T ", " . y 5.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++`S]T%Ek$x#Y@G#uIG*x$Q+p$G%h;%Ej@j#+T^TJ]i#j=l;)*=$e=h=_*_*,->~ZQ/T(T7RP%RSn&RPz^D$--c=p&:#7@C@h@R{g@x6Qe_T@Ego:T/+@8&b=:#3@w#C@n#D-0@RLb@i;7&$*|T,-;-)S:*OS[%<%_*k/1T2T<%3TRS>~t%1>I-4&}!:$z@~-Wf;#$Er@g@L#p']>4T5T6TTv7T ", " . y .+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++8T9T$-+B@-M#E@z%0TaTqB1>)*bT|+cTbTdTeT)*q$J-fTJ-J-K%k&@{ RgTuS>~xShT|!iTjTkT>~c)vSlTm&[%5&($l+U+I*O+@-iMp$q;d=&,w%mTnTbRoTpT ", " . y 6.qTrTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTrTtTuTvTwTxTgpyTzT@vAToQBTCTF@DTETFTGTHT,@ITJTKTLTMTNTOTPTQTRTSTTTUTVTWTXTYTZTUT`T U.U+U@U,@#U$U%U*E&U*U=U-U;U>U,U#U'U)U!U~U{U ", " . ]U^U/U(U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U_U(U:UV,V'V)V!V~V{V]V,V^V/V(V_V:VW,W'W)WoT!W~W{W]W^WKU/WEN(W^W/W_W:W Set maximum framerate to (default: 200, availble: 1-200) ;-hogdir set shared data directory to ;-nohogdir don't try to use shared data directory ;-use_players_dir put player files and saved games in Players subdirectory ;-lowmem Lowers animation detail for better performance with low memory ;-pilot Select pilot automatically ;-autodemo Start in demo mode ;-notitles Skip title screens ;-window Run the game in a window ;-noborders Do not show borders in window mode Controls: ;-nocursor Hide mouse cursor ;-nomouse Deactivate mouse ;-nojoystick Deactivate joystick ;-nostickykeys Make CapsLock and NumLock non-sticky Sound: ;-nosound Disables sound output ;-nomusic Disables music output ;-nosdlmixer Disable Sound output via SDL_mixer Graphics: ;-lowresfont Force to use LowRes fonts ;-gl_fixedfont Do not scale fonts to current resolution Multiplayer: ;-udp_hostaddr Use IP address/Hostname for manual game joining (default: localhost) ;-udp_hostport Use UDP port for manual game joining (default: 42424) ;-udp_myport Set my own UDP port to (default: 42424) ;-tracker_hostaddr Address of Tracker server to register/query games to/from (default: dxxtracker.reenigne.net) ;-tracker_hostport Port of Tracker server to register/query games to/from (default: 42420) Debug (use only if you know what you're doing): ;-debug Enable debugging output. ;-verbose Enable verbose output. ;-safelog Write gamelog.txt unbuffered. Use to keep helpful output to trace program crashes. ;-norun Bail out after initialization ;-renderstats Enable renderstats info by default ;-text Specify alternate .tex file ;-tmap Select texmapper to use (default: c, available: c, fp, quad, i386) ;-showmeminfo Show memory statistics ;-nodoublebuffer Disable Doublebuffering ;-bigpig Use uncompressed RLE bitmaps ;-16bpp Use 16Bpp instead of 32Bpp ;-gl_oldtexmerge Use old texmerge, uses more ram, but might be faster ;-gl_intensity4_ok Override DbgGlIntensity4Ok (default: 1) ;-gl_luminance4_alpha4_ok Override DbgGlLuminance4Alpha4Ok (default: 1) ;-gl_rgba2_ok Override DbgGlRGBA2Ok (default: 1) ;-gl_readpixels_ok Override DbgGlReadPixelsOk (default: 1) ;-gl_gettexlevelparam_ok Override DbgGlGetTexLevelParamOk (default: 1) dxx-rebirth-0.58.1-d1x/d1xgl-Info.plist000066400000000000000000000014331217717257200175400ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable d1xgl CFBundleIconFile d1x-rebirth CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature DCNT CFBundleVersion 0.57.3 CSResourcesFileMapped LSPrefersCarbon NSMainNibFile MainMenu NSPrincipalClass NSApplication dxx-rebirth-0.58.1-d1x/debian/000077500000000000000000000000001217717257200157745ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/debian/changelog000066400000000000000000000004231217717257200176450ustar00rootroot00000000000000d1x-rebirth (0.56-1) maverick; urgency=low * Keeping up to date. -- zico Thu, 05 May 2011 01:22:39 +0100 d1x-rebirth (0.55-1) intrepid; urgency=low * Package creation. -- MD2211 Tue, 30 Dec 2008 16:18:17 +0100 dxx-rebirth-0.58.1-d1x/debian/control000066400000000000000000000011611217717257200173760ustar00rootroot00000000000000Source: d1x-rebirth Section: games Priority: optional Maintainer: zico Standards-Version: 3.6.1 Package: d1x-rebirth Build-Depends: libsdl1.2-dev, libsdl-mixer1.2-dev, libphysfs-dev, scons Recommends: timidity, freepats Architecture: any Depends: ${shlibs:Depends} Description: Port of the 1995 classic game Descent 1: First Strike DXX-Rebirth is a Source Port of the Descent & Descent ][ Engines and provides classical Gameplay combined with OpenGL graphics and effects, a bunch of improvements and new features. . For more information please visit the web site: http://www.dxx-rebirth.com/ dxx-rebirth-0.58.1-d1x/debian/copyright000066400000000000000000000005361217717257200177330ustar00rootroot00000000000000This software was packaged by zico Thu, 05 May 2011 01:22:39 +0100 It was downloaded from: http://www.dxx-rebirth.com/ Original authors: * Descent 1 by Interplay / Parallax Software * D1X by Sekmu * DXX-Rebirth by Zico License: Please see COPYING file for details dxx-rebirth-0.58.1-d1x/debian/patches/000077500000000000000000000000001217717257200174235ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/debian/patches/00games_as_bindir.diff000066400000000000000000000005361217717257200235270ustar00rootroot00000000000000--- SConstruct 2008-12-30 21:47:01.000000000 +0100 +++ SConstruct.new 2008-12-30 21:47:44.000000000 +0100 @@ -15,7 +15,7 @@ # installation path PREFIX = str(ARGUMENTS.get('prefix', '/usr/local')) -BIN_SUBDIR = '/bin' +BIN_SUBDIR = '/games' DATA_SUBDIR = '/share/games/d1x-rebirth' BIN_DIR = PREFIX + BIN_SUBDIR DATA_DIR = PREFIX + DATA_SUBDIR dxx-rebirth-0.58.1-d1x/debian/postinst000077500000000000000000000000151217717257200176010ustar00rootroot00000000000000#! /bin/bash dxx-rebirth-0.58.1-d1x/debian/prerm000077500000000000000000000000151217717257200170430ustar00rootroot00000000000000#! /bin/bash dxx-rebirth-0.58.1-d1x/debian/rules000077500000000000000000000041531217717257200170570ustar00rootroot00000000000000#! /usr/bin/make -f # # debian/rules file for d1x-rebirth # zico # Thu, 05 May 2011 01:22:39 +0100 # package = d1x-rebirth SCONS = scons -Q SCONSFLAGS = prefix=/usr BINARY = d1x-rebirth PREFIX = /usr BIN_DIR = $(PREFIX)/games SHARE_DIR = $(PREFIX)/share DATA_DIR = $(SHARE_DIR)/games/$(package) DEBIAN_TMP = debian/tmp patch: patch-stamp patch-stamp: test -d debian/patches @for patch in debian/patches/*.diff; do \ echo "Applying $$patch"; \ patch < $$patch; \ done touch $@ build: patch build-stamp build-stamp: $(SCONS) $(SCONSFLAGS) strip $(BINARY) touch $@ clean: $(SCONS) -c rm -rf patch-stamp build-stamp *~ $(DEBIAN_TMP) debian/*~ debian/files* debian/substvars binary-indep: checkroot $(checkdir) # There are no architecture-independent files to be uploaded # generated by this package. If there were any they would be # made here. TMP_BIN_DIR = $(DEBIAN_TMP)/$(BIN_DIR) TMP_SHARE_DIR = $(DEBIAN_TMP)/$(SHARE_DIR) TMP_DATA_DIR = $(DEBIAN_TMP)/$(DATA_DIR) binary-arch: checkroot build $(checkdir) rm -rf $(DEBIAN_TMP) install -d $(DEBIAN_TMP)/DEBIAN $(TMP_BIN_DIR) $(TMP_DATA_DIR) install -d $(TMP_DATA_DIR)/missions $(TMP_DATA_DIR)/demos $(TMP_DATA_DIR)/screenshots $(TMP_DATA_DIR)/Music install -d $(TMP_SHARE_DIR)/applications $(TMP_SHARE_DIR)/pixmaps install -m 755 debian/postinst debian/prerm $(DEBIAN_TMP)/DEBIAN install -m 755 $(BINARY) $(TMP_BIN_DIR) install -m 644 d1x.ini $(TMP_DATA_DIR) install -m 644 CHANGELOG.txt $(TMP_DATA_DIR) install -m 644 COPYING.txt $(TMP_DATA_DIR) install -m 644 README.txt $(TMP_DATA_DIR) unzip d1xr-hires.zip -d $(TMP_DATA_DIR) install -m 644 d1x-rebirth.desktop $(TMP_SHARE_DIR)/applications install -m 644 d1x-rebirth.xpm $(TMP_SHARE_DIR)/pixmaps dpkg-shlibdeps $(TMP_BIN_DIR)/$(BINARY) dpkg-gencontrol -isp chown -R root:root $(DEBIAN_TMP) chmod -R u+w,go=rX $(DEBIAN_TMP) dpkg --build $(DEBIAN_TMP) .. define checkdir test -f SConstruct -a -f debian/rules endef binary: binary-indep binary-arch checkroot: $(checkdir) test $$(id -u) = 0 .PHONY: binary binary-arch binary-indep clean checkroot dxx-rebirth-0.58.1-d1x/editor/000077500000000000000000000000001217717257200160405ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/editor/autosave.c000066400000000000000000000103541217717257200200360ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Autosave system: * Saves current mine to disk to prevent loss of work, and support undo. * */ #include #include #include #include #include #include #include "dxxerror.h" #include "inferno.h" #include "editor.h" #include "u_mem.h" #include "ui.h" #include "strutil.h" #define AUTOSAVE_PERIOD 5 // Number of minutes for timed autosave int Autosave_count; int Autosave_numfiles; int Autosave_total; int undo_count; int original; int Timer_save_flag=0; int Autosave_flag; int save_second=-1; char undo_status[10][100]; void init_autosave(void) { // int i; Autosave_count = 0; Autosave_numfiles = 0; Autosave_flag = 0; undo_count = 0; //MALLOC( undo_status, char *, 10 ); //for (i=0; i<10; i++) // MALLOC( undo_status[i], char, 100 ); autosave_mine(mine_filename); } void close_autosave(void) { int i; char *delname, *ext; for (i=0;i 0) undo_count--; if (Autosave_count > 9) Autosave_count -= 10; if (Autosave_numfiles < 10) Autosave_numfiles++; if (Autosave_total < 10) Autosave_total++; d_free(savename); } } void print_clock( int seconds, char message[10] ) { int w,h,aw; char *p; // Make colon flash if (seconds & 1) if ((p = strchr(message, ':')) != NULL) *p = ' '; gr_set_current_canvas( NULL ); gr_set_fontcolor( CBLACK, CGREY ); gr_get_string_size( message, &w, &h, &aw ); gr_setcolor( CGREY ); gr_rect( 700, 0, 799, h+1 ); gr_string( 700, 0, message ); gr_set_fontcolor( CBLACK, CWHITE ); } static char the_time[14]; // changed from 10, I don't think that was long enough void clock_message( int seconds, char *format, ... ) { va_list ap; va_start(ap, format); vsprintf(the_time, format, ap); va_end(ap); print_clock(seconds, the_time); } struct tm Editor_time_of_day; void set_editor_time_of_day() { time_t ltime; time( <ime ); Editor_time_of_day = *localtime( <ime ); } void TimedAutosave(char *name) { int month,day,hour,minute,second; month = (Editor_time_of_day.tm_mon) + 1; day = Editor_time_of_day.tm_mday; minute = Editor_time_of_day.tm_min; hour = Editor_time_of_day.tm_hour; second = Editor_time_of_day.tm_sec; if (hour > 12) hour-=12; //if (second!=save_second) { save_second = second; clock_message(second, "%d/%d %d:%02d", month, day, hour, minute); } #ifndef DEMO if (minute%AUTOSAVE_PERIOD != 0) Timer_save_flag = 1; if ((minute%AUTOSAVE_PERIOD == 0) && (Timer_save_flag)) { time_t ltime; autosave_mine(name); Timer_save_flag = 0; time( <ime ); diagnostic_message_fmt("Mine Autosaved at %s\n", ctime(<ime)); } #endif } int undo( void ) { Int3(); return 2; } dxx-rebirth-0.58.1-d1x/editor/centers.c000066400000000000000000000152601217717257200176530ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Dialog box stuff for control centers, material centers, etc. * */ #include #include #include #include #include "fuelcen.h" #include "screens.h" #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "timer.h" #include "objpage.h" #include "fix.h" #include "dxxerror.h" #include "kdefs.h" #include "object.h" #include "polyobj.h" #include "game.h" #include "powerup.h" #include "ai.h" #include "hostage.h" #include "eobject.h" #include "medwall.h" #include "eswitch.h" #include "ehostage.h" #include "key.h" #include "medrobot.h" #include "bm.h" #include "centers.h" //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- static UI_DIALOG *MainWindow = NULL; typedef struct centers_dialog { UI_GADGET_BUTTON *quitButton; UI_GADGET_RADIO *centerFlag[MAX_CENTER_TYPES]; UI_GADGET_CHECKBOX *robotMatFlag[MAX_ROBOT_TYPES]; int old_seg_num; } centers_dialog; char center_names[MAX_CENTER_TYPES][CENTER_STRING_LENGTH] = { "Nothing", "FuelCen", "RepairCen", "ControlCen", "RobotMaker" }; int centers_dialog_handler(UI_DIALOG *dlg, d_event *event, centers_dialog *c); //------------------------------------------------------------------------- // Called from the editor... does one instance of the centers dialog box //------------------------------------------------------------------------- int do_centers_dialog() { centers_dialog *c; int i; // Only open 1 instance of this window... if ( MainWindow != NULL ) return 0; // Close other windows. close_trigger_window(); hostage_close_window(); close_wall_window(); robot_close_window(); MALLOC(c, centers_dialog, 1); if (!c) return 0; // Open a window with a quit button MainWindow = ui_create_dialog( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, (int (*)(UI_DIALOG *, d_event *, void *))centers_dialog_handler, c ); c->quitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL ); // These are the checkboxes for each door flag. i = 80; c->centerFlag[0] = ui_add_gadget_radio( MainWindow, 18, i, 16, 16, 0, "NONE" ); i += 24; c->centerFlag[1] = ui_add_gadget_radio( MainWindow, 18, i, 16, 16, 0, "FuelCen" ); i += 24; c->centerFlag[2] = ui_add_gadget_radio( MainWindow, 18, i, 16, 16, 0, "RepairCen" ); i += 24; c->centerFlag[3] = ui_add_gadget_radio( MainWindow, 18, i, 16, 16, 0, "ControlCen" ); i += 24; c->centerFlag[4] = ui_add_gadget_radio( MainWindow, 18, i, 16, 16, 0, "RobotCen" ); i += 24; // These are the checkboxes for each robot flag. for (i=0; irobotMatFlag[i] = ui_add_gadget_checkbox( MainWindow, 128 + (i%2)*92, 20+(i/2)*24, 16, 16, 0, Robot_names[i]); c->old_seg_num = -2; // Set to some dummy value so everything works ok on the first frame. return 1; } void close_centers_window() { if ( MainWindow!=NULL ) { ui_close_dialog( MainWindow ); MainWindow = NULL; } } int centers_dialog_handler(UI_DIALOG *dlg, d_event *event, centers_dialog *c) { int i; // int robot_flags; int keypress = 0; int rval = 0; Assert(MainWindow != NULL); if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; //------------------------------------------------------------ // If we change centers, we need to reset the ui code for all // of the checkboxes that control the center flags. //------------------------------------------------------------ if (c->old_seg_num != Cursegp-Segments) { for (i = 0; i < MAX_CENTER_TYPES; i++) ui_radio_set_value(c->centerFlag[i], 0); Assert(Cursegp->special < MAX_CENTER_TYPES); ui_radio_set_value(c->centerFlag[Cursegp->special], 1); // Read materialization center robot bit flags for (i = 0; i < N_robot_types; i++) ui_checkbox_check(c->robotMatFlag[i], RobotCenters[Cursegp->matcen_num].robot_flags[0] & (1 << i)); } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the corresponding center. //------------------------------------------------------------ for ( i=0; i < MAX_CENTER_TYPES; i++ ) { if ( GADGET_PRESSED(c->centerFlag[i]) ) { if ( i == 0) fuelcen_delete(Cursegp); else if (Cursegp->special != i) { fuelcen_delete(Cursegp); Update_flags |= UF_WORLD_CHANGED; fuelcen_activate( Cursegp, i ); } rval = 1; } } for (i = 0; i < N_robot_types; i++) { if ( GADGET_PRESSED(c->robotMatFlag[i]) ) { if (c->robotMatFlag[i]->flag) RobotCenters[Cursegp->matcen_num].robot_flags[0] |= (1 << i); else RobotCenters[Cursegp->matcen_num].robot_flags[0] &= ~(1 << i); rval = 1; } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this wall. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { // int i; // char temp_text[CENTER_STRING_LENGTH]; ui_dprintf_at( dlg, 12, 6, "Seg: %3ld", Cursegp-Segments ); // for (i=0; ispecial < MAX_CENTER_TYPES); // strncpy(temp_text, Center_names[Cursegp->special], strlen(Center_names[Cursegp->special])); // ui_dprintf_at( dlg, 12, 23, " Type: %s", temp_text ); } if (c->old_seg_num != Cursegp-Segments) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(c); MainWindow = NULL; return 0; // we're not cancelling the close } if ( GADGET_PRESSED(c->quitButton) || (keypress==KEY_ESC) ) { close_centers_window(); return 1; } c->old_seg_num = Cursegp-Segments; return rval; } dxx-rebirth-0.58.1-d1x/editor/curves.c000066400000000000000000000416151217717257200175220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * curve generation stuff * */ #include #include #include #include #include #include #include "inferno.h" #include "vecmat.h" #include "gr.h" #include "key.h" #include "editor.h" #include "editor/esegment.h" #include "gameseg.h" #include "console.h" #define ONE_OVER_SQRT2 F1_0 * 0.707106781 #define CURVE_RIGHT 1 #define CURVE_UP 2 segment *OriginalSeg; segment *OriginalMarkedSeg; int OriginalSide; int OriginalMarkedSide; segment *CurveSegs[MAX_SEGMENTS]; int CurveNumSegs; const fix Mh[4][4] = { { 2*F1_0, -2*F1_0, 1*F1_0, 1*F1_0 }, {-3*F1_0, 3*F1_0, -2*F1_0, -1*F1_0 }, { 0*F1_0, 0*F1_0, 1*F1_0, 0*F1_0 }, { 1*F1_0, 0*F1_0, 0*F1_0, 0*F1_0 } }; void generate_banked_curve(fix maxscale, vms_equation coeffs); void create_curve(vms_vector *p1, vms_vector *p4, vms_vector *r1, vms_vector *r4, vms_equation *coeffs) { // Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t~3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4 coeffs->n.x3 = fixmul(2*F1_0,p1->x) - fixmul(2*F1_0,p4->x) + r1->x + r4->x; coeffs->n.x2 = fixmul(-3*F1_0,p1->x) + fixmul(3*F1_0,p4->x) - fixmul(2*F1_0,r1->x) - fixmul(1*F1_0,r4->x); coeffs->n.x1 = r1->x; coeffs->n.x0 = p1->x; coeffs->n.y3 = fixmul(2*F1_0,p1->y) - fixmul(2*F1_0,p4->y) + r1->y + r4->y; coeffs->n.y2 = fixmul(-3*F1_0,p1->y) + fixmul(3*F1_0,p4->y) - fixmul(2*F1_0,r1->y) - fixmul(1*F1_0,r4->y); coeffs->n.y1 = r1->y; coeffs->n.y0 = p1->y; coeffs->n.z3 = fixmul(2*F1_0,p1->z) - fixmul(2*F1_0,p4->z) + r1->z + r4->z; coeffs->n.z2 = fixmul(-3*F1_0,p1->z) + fixmul(3*F1_0,p4->z) - fixmul(2*F1_0,r1->z) - fixmul(1*F1_0,r4->z); coeffs->n.z1 = r1->z; coeffs->n.z0 = p1->z; } vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t) { fix t2, t3; vms_vector coord; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); t2 = fixmul(t,t); t3 = fixmul(t2,t); coord.x = fixmul(coeffs->n.x3,t3) + fixmul(coeffs->n.x2,t2) + fixmul(coeffs->n.x1,t) + coeffs->n.x0; coord.y = fixmul(coeffs->n.y3,t3) + fixmul(coeffs->n.y2,t2) + fixmul(coeffs->n.y1,t) + coeffs->n.y0; coord.z = fixmul(coeffs->n.z3,t3) + fixmul(coeffs->n.z2,t2) + fixmul(coeffs->n.z1,t) + coeffs->n.z0; return coord; } fix curve_dist(vms_equation *coeffs, int degree, fix t0, vms_vector *p0, fix dist) { vms_vector coord; fix t, diff; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); for (t=t0;t<1*F1_0;t+=0.001*F1_0) { coord = evaluate_curve(coeffs, 3, t); diff = dist - vm_vec_dist(&coord, p0); if (diff-ACCURACY)) return t; } return -1*F1_0; } void curve_dir(vms_equation *coeffs, int degree, fix t0, vms_vector *dir) { fix t2; if (degree!=3) con_printf(CON_CRITICAL," for Hermite Curves degree must be 3\n"); t2 = fixmul(t0,t0); dir->x = fixmul(3*F1_0,fixmul(coeffs->n.x3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.x2,t0)) + coeffs->n.x1; dir->y = fixmul(3*F1_0,fixmul(coeffs->n.y3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.y2,t0)) + coeffs->n.y1; dir->z = fixmul(3*F1_0,fixmul(coeffs->n.z3,t2)) + fixmul(2*F1_0,fixmul(coeffs->n.z2,t0)) + coeffs->n.z1; vm_vec_normalize( dir ); } void plot_parametric(vms_equation *coeffs, fix min_t, fix max_t, fix del_t) { vms_vector coord, dcoord; fix t, dt; gr_setcolor(15); gr_box( 75, 40, 325, 290 ); gr_box( 75, 310, 325, 560 ); gr_box( 475, 310, 725, 560 ); //gr_pal_fade_in( grd_curscreen->pal ); for (t=min_t;t fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat,rotmat2; vms_vector tdest; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(Cursegp, &tvec); nextdist = vm_vec_mag(&tvec); // nextdist := distance to next point t = curve_dist(&coeffs, 3, t, &prev_point, nextdist); // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(&coord, &p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(&vec_dir, &coord, &prev_point); if (!med_attach_segment( Cursegp, &New_segment, Curside, AttachSide )) { med_extract_matrix_from_segment( Cursegp,&rotmat ); // rotmat := matrix describing orientation of Cursegp vm_vec_rotate(&tdest,&vec_dir,&rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; vm_vector_2_matrix(&rotmat2,&vec_dir,NULL,NULL); med_rotate_segment( Cursegp, &rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } else return 0; } extract_up_vector_from_segment( Cursegp,&tvec ); uangle = vm_vec_delta_ang( &tvec, &r4t, &r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment( Cursegp,&tvec ); rangle = vm_vec_delta_ang( &tvec, &r4t, &r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if ((uangle != 0) && (rangle != 0)) { maxscale = CurveNumSegs*F1_0; generate_banked_curve(maxscale, coeffs); } if (CurveNumSegs) { med_form_bridge_segment( Cursegp, Side_opposite[AttachSide], Markedsegp, Markedside ); CurveSegs[CurveNumSegs] = &Segments[ Markedsegp->children[Markedside] ]; CurveNumSegs++; } Cursegp = OriginalSeg; Curside = OriginalSide; med_create_new_segment_from_cursegp(); //warn_if_concave_segments(); if (CurveNumSegs) return 1; else return 0; } void generate_banked_curve(fix maxscale, vms_equation coeffs) { vms_vector vec_dir, tvec, b4r4t; vms_vector coord,prev_point; fix enddist, nextdist; int firstsegflag; fixang rangle, uangle, angle, scaled_ang=0; fix t; if (CurveNumSegs) { extract_up_vector_from_segment( Cursegp,&b4r4t ); uangle = vm_vec_delta_ang( &b4r4t, &r4t, &r4 ); if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4; extract_right_vector_from_segment( Cursegp,&b4r4t ); rangle = vm_vec_delta_ang( &b4r4t, &r4t, &r4 ); if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle >= F1_0/8) rangle -= F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; if (rangle <= -F1_0/8) rangle += F1_0/4; angle = uangle; if (abs(rangle) < abs(uangle)) angle = rangle; delete_curve(); coord = prev_point = p1; #define MAGIC_NUM 0.707*F1_0 if (maxscale) scaled_ang = fixdiv(angle,fixmul(maxscale,MAGIC_NUM)); t=0; tvec = r1save; firstsegflag = 1; enddist = F1_0; nextdist = 0; while ( enddist > fixmul( nextdist, 1.5*F1_0 )) { vms_matrix rotmat,rotmat2; vms_vector tdest; if (firstsegflag==1) firstsegflag=0; else extract_forward_vector_from_segment(Cursegp, &tvec); nextdist = vm_vec_mag(&tvec); // nextdist := distance to next point t = curve_dist(&coeffs, 3, t, &prev_point, nextdist); // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve) coord = evaluate_curve(&coeffs, 3, t); // coord := point about forward vector magnitude units away from prev_point enddist = vm_vec_dist(&coord, &p4); // enddist := distance from current to end point, vec_dir used as a temporary variable //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point)); vm_vec_normalized_dir(&vec_dir, &coord, &prev_point); if (!med_attach_segment( Cursegp, &New_segment, Curside, AttachSide )) { med_extract_matrix_from_segment( Cursegp,&rotmat ); // rotmat := matrix describing orientation of Cursegp vm_vec_rotate(&tdest,&vec_dir,&rotmat); // tdest := vec_dir in reference frame of Cursegp vec_dir = tdest; vm_vec_ang_2_matrix(&rotmat2,&vec_dir,scaled_ang); med_rotate_segment( Cursegp, &rotmat2 ); prev_point = coord; Curside = Side_opposite[AttachSide]; CurveSegs[CurveNumSegs]=Cursegp; CurveNumSegs++; } } } } void delete_curve() { int i; for (i=0; isegnum != -1) med_delete_segment(CurveSegs[i]); } Markedsegp = OriginalMarkedSeg; Markedside = OriginalMarkedSide; Cursegp = OriginalSeg; Curside = OriginalSide; med_create_new_segment_from_cursegp(); CurveNumSegs = 0; //editor_status(""); //warn_if_concave_segments(); } /* void main() { vms_vector p1; vms_vector p4; vms_vector r1; vms_vector r4; vms_equation coeffs; float x, y, z; vms_vector test, test2, tvec; fix t, t0; fix distance, dist; int key; key_init(); printf("Enter p1 (x,y,z): "); scanf("%f %f %f", &x, &y, &z); p1.x = x*F1_0; p1.y = y*F1_0; p1.z = z*F1_0; printf("Enter p4 (x,y,z): "); scanf("%f %f %f", &x, &y, &z); p4.x = x*F1_0; p4.y = y*F1_0; p4.z = z*F1_0; printf("Enter r1 : "); scanf("%f %f %f", &x, &y, &z); r1.x = x*F1_0; r1.y = y*F1_0; r1.z = z*F1_0; printf("Enter r4 : "); scanf("%f %f %f", &x, &y, &z); r4.x = x*F1_0; r4.y = y*F1_0; r4.z = z*F1_0; create_curve( &p1, &p4, &r1, &r4, &coeffs ); printf("\nQ(t) = "); printf("x [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.x3), f2fl(coeffs.n.x2), f2fl(coeffs.n.x1), f2fl(coeffs.n.x0)); printf(" y [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.y3), f2fl(coeffs.n.y2), f2fl(coeffs.n.y1), f2fl(coeffs.n.y0)); printf(" z [%6.3f %6.3f %6.3f %6.3f]\n", f2fl(coeffs.n.z3), f2fl(coeffs.n.z2), f2fl(coeffs.n.z1), f2fl(coeffs.n.z0)); printf("\nChecking direction vectors.\n"); for (t=0*F1_0;t<1*F1_0;t+=0.1*F1_0) { curve_dir(&coeffs, 3, t, &test); printf(" t = %.3f dir = <%6.3f, %6.3f, %6.3f >\n", f2fl(t), f2fl(test.x), f2fl(test.y), f2fl(test.z) ); } printf("\nChecking distance function.\n"); printf("Enter a distance: "); scanf("%f", &x); distance = x*F1_0; printf("Enter a (0þ><~~<fffffffffÛÛÛ{|Æ`8lÆÆl8 Æ|þþþþ<~~<~<~~< þ 0`þ`0ÀÀÀþ(lþl(88||þþþþ||88<<<fff$llþlllþll|ÆÂÀ|†Æ|ÂÆ 0`Ɔ8ll8vÜÌÌÌv000` 000000 0 0f<ÿlÌÌþÌÌÌÌÎ8l|ÆÆÆÆÆ|Æ|ÆÆÆÆÆ|`0|ÆÆÆÆÆ|0xÌÌÌÌÌÌÌv`0ÌÌÌÌÌÌvÆÆÆÆÆÆÆ~ xÆ|ÆÆÆÆÆÆÆ|ÆÆÆÆÆÆÆÆÆ|~8ll8|0000`ÀÆÆ|þÀÀÀÀþÀÀÂÆÌ0`܆ >ÀÀÂÆÌ0fΞ><<<6lØl6Øl6lØDDDDDDDDUªUªUªUªUªUªUªUªÝwÝwÝwÝwÝwÝwÝwÝwøøø6666666ö66666666þ66666666øø66666öö666666666666666666666666þö6666666666666öþ6666666þøøøÿÿÿÿ66666667666666666666670??076666666666666÷ÿÿ÷666666666666670766666666ÿÿ66666÷÷66666666ÿÿ6666666ÿÿÿÿ666666666666666??666666666666666ÿ66666666ÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿððððððððððððððððÿÿÿÿÿÿÿvÜØØØÜvxÌÌÌØÌÆÆÆÌþÆÆÀÀÀÀÀÀÀþlllllllþÆ`00`Æþ~ØØØØØpfffff|``ÀvÜ~ffff<~ÛÛÛ~~ÛÛó~`À0``|```0|ÆÆÆÆÆÆÆÆþþþ~ÿ0  0~ 0`0 ~ØØØp~vÜvÜ8ll8 ìll<ØlllllpØ0`Èø|||||||dxx-rebirth-0.58.1-d1x/editor/data/segmove.pad000066400000000000000000000020521217717257200211030ustar00rootroot00000000000000Segment rotation ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ¿ ³ Num ³ / ³ * ³ - ³ ³ Lock ³ ³ ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ 7 ³ Pitch ³ 9 ³ ³ ³ Home ³ Forward³ PgUp ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ + ³ ³ Rotate ³ 5 ³ Rotate ³ ³ ³ Left ³ ³ Right ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ Bank ³ Pitch ³ Bank ³ ³ ³ Left ³Backward³ Right ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ Enter ³ ³ 0 ³ . ³ ³ ³ Ins ³ Del ³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÙ {Ctrl}{Pad8} med-segmove-increase-pitch {Ctrl}{Pad2} med-segmove-decrease-pitch {Ctrl}{Pad4} med-segmove-decrease-heading {Ctrl}{Pad6} med-segmove-increase-heading {Ctrl}{Pad1} med-segmove-decrease-bank {Ctrl}{Pad3} med-segmove-increase-bank dxx-rebirth-0.58.1-d1x/editor/data/segsize.pad000066400000000000000000000036171217717257200211170ustar00rootroot00000000000000Segment Scaling Mode ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ¿ ³ Num ³Increase³Increase³Increase³ ³ Lock ³Length ³Width ³Height ³ ³ ³Default ³Default ³Default ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ 7 ³Increase³Increase³ ³ ³ Home ³Length ³Height ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ Perturb³ ³Decrease³ 5 ³Increase³ Curside³ ³Width ³ ³Width ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ 1 ³Decrease³Decrease³ ³ ³ End ³Length ³Height ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ Next ³ ³ 0 ³ . ³ Edge ³ ³ Select Next ³ Next ³ ³ ³ Mode ³ Vertex ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÙ {Ctrl}{Pad6} med-segsize-increase-width {Ctrl}{Pad8} med-segsize-increase-length {Ctrl}{Pad9} med-segsize-increase-height {Ctrl}{Pad4} med-segsize-decrease-width {Ctrl}{Pad2} med-segsize-decrease-length {Ctrl}{Pad3} med-segsize-decrease-height {Ctrl}{Shift}{Pad6} med-segsize-increase-width-big {Ctrl}{Shift}{Pad8} med-segsize-increase-length-big {Ctrl}{Shift}{Pad9} med-segsize-increase-height-big {Ctrl}{Shift}{Pad4} med-segsize-decrease-width-big {Ctrl}{Shift}{Pad2} med-segsize-decrease-length-big {Ctrl}{Shift}{Pad3} med-segsize-decrease-height-big {Ctrl}{Pad0} med-segsize-toggle-mode {Ctrl}{Pad.} med-light-select-next-vertex {Ctrl}{PadEnter} med-light-select-next-edge {Ctrl}{Pad+} med-segsize-perturb-curside {Ctrl}{Shift}{Pad+} med-segsize-perturb-curside-big {Ctrl}{Pad/} med-segsize-increase-length-default {Ctrl}{Pad*} med-segsize-increase-width-default {Ctrl}{Pad-} med-segsize-increase-height-default {Ctrl}{Shift}{Pad/} med-segsize-decrease-length-default {Ctrl}{Shift}{Pad*} med-segsize-decrease-width-default {Ctrl}{Shift}{Pad-} med-segsize-decrease-height-default dxx-rebirth-0.58.1-d1x/editor/data/test.pad000066400000000000000000000016031217717257200204160ustar00rootroot00000000000000Temporary Test Functions ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ¿ ³ Num ³ / ³ * ³ - ³ ³ Lock ³ ³ ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ 7 ³ 8 ³ 9 ³ ³ ³ Home ³  ³ PgUp ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ + ³ ³ 4 ³ 5 ³ 6 ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ Test ³ Test ³ Test ³ ³ ³Function³Function³Function³ ³ ³ 1 ³ 2 ³ 3 ³ ³ ÃÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ Enter ³ ³ 0 ³ . ³ ³ ³ Ins ³ Del ³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÙ {Ctrl}{Pad1} med-test-1 {Ctrl}{Pad2} med-test-2 {Ctrl}{Pad3} med-test-3 dxx-rebirth-0.58.1-d1x/editor/data/texture.pad000066400000000000000000000030661217717257200211440ustar00rootroot00000000000000Texture Mapping Functions ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ¿ ³ Remap ³ Flip ³ Flip ³ Remap ³ ³ Crsd to³ in X ³ in Y ³ Tmap2 ³ ³ Current³ ³ ³ to Curr³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ Stretch³ Slide ³ Stretch³ ³ ³ Less ³ Up ³ More ³ Set ³ ³ ³ ³ ³ Default³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ in ³ ³ Slide ³ Set ³ Slide ³Selected³ ³ Left ³ Default³ Right ³ List ³ ³ ³ ³ ³ ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ ³ Rotate ³ Slide ³ Rotate ³ ³ ³ Left ³ Down ³ Right ³ ³ ³ ³ ³ ³ Select ³ ÃÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ´ Active ³ ³ Rotate ³ Next ³ Edge ³ ³ 90 degrees ³ Edge ³ ³ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÙ {Ctrl}{Pad/} med-tass-flip-x {Ctrl}{Pad*} med-tass-flip-y {Ctrl}{Pad8} med-tass-slide-up {Ctrl}{Pad4} med-tass-slide-left {Ctrl}{Pad5} med-tass-set-default {Ctrl}{Pad6} med-tass-slide-right {Ctrl}{Pad7} med-tass-stretch-down {Ctrl}{Pad9} med-tass-stretch-up {Ctrl}{Pad1} med-tass-rotate-left {Ctrl}{Pad2} med-tass-slide-down {Ctrl}{Pad3} med-tass-rotate-right {Ctrl}{PadEnter} med-tass-select-active-edge {Ctrl}{Pad0} med-tass-rotate-90-degrees {Ctrl}{Pad.} med-light-select-next-edge {Ctrl}{Shift}{Pad8} med-tass-slide-up-big {Ctrl}{Shift}{Pad4} med-tass-slide-left-big {Ctrl}{Shift}{Pad6} med-tass-slide-right-big {Ctrl}{Shift}{Pad1} med-tass-rotate-left-big {Ctrl}{Shift}{Pad2} med-tass-slide-down-big {Ctrl}{Shift}{Pad3} med-tass-rotate-right-big dxx-rebirth-0.58.1-d1x/editor/eglobal.c000066400000000000000000000072141217717257200176150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Globals for editor. * */ #include #include "inferno.h" #include "segment.h" #include "editor.h" // Global pointer to current vertices, right now always Vertices. Set in create_new_mine. segment New_segment; // The segment which can be added to the mine. segment *Cursegp = NULL; // Pointer to current segment in mine. int Curside; // Side index in 0..MAX_SIDES_PER_SEGMENT of active side. int Curedge; // Current edge on current side, in 0..3 int Curvert; // Current vertex on current side, in 0..3 int AttachSide = WFRONT; // Side on segment to attach. segment *Markedsegp = NULL; // Marked segment, used in conjunction with *Cursegp to form joints. int Markedside; // Marked side on Markedsegp. int Draw_all_segments; // Set to 1 means draw_world draws all segments in Segments, else draw only connected segments sbyte Vertex_active[MAX_VERTICES]; // !0 means vertex is in use, 0 means not in use. int N_selected_segs = 0; // Number of segments found at Selected_segs short Selected_segs[MAX_SELECTED_SEGS]; // List of segment numbers currently selected int N_warning_segs = 0; // Number of segments warning-worthy, such as a concave segment short Warning_segs[MAX_WARNING_SEGS]; // List of segment numbers currently selected int N_found_segs = 0; // Number of segments found with last shift-mouse-click short Found_segs[MAX_FOUND_SEGS]; // List of warning-worthy segments int Show_axes_flag = 0; // 0 = don't show, !0 = do show coordinate axes in *Cursegp orientation sbyte Been_visited[MAX_SEGMENTS]; // List of segments visited in a recursive search, if element n set, segment n done been visited // Variables global to this editor.c and the k?????.c files. uint Update_flags = UF_ALL; //force total redraw int Funky_chase_mode = 0; vms_angvec Seg_orientation = {0,0,0}; vms_vector Seg_scale = {F1_0*20,F1_0*20,F1_0*20}; int mine_changed = 0; int ModeFlag; editor_view *current_view; int SegSizeMode = 1; // Mode = 0/1 = not/is legal to move bound vertices, //the view for the different windows. editor_view LargeView = {0,1, NULL, i2f(100),IDENTITY_MATRIX,f1_0}; #if ORTHO_VIEWS editor_view TopView = {1,1, NULL, i2f(100),{{f1_0,0,0},{0,0,-f1_0},{0,f1_0,0}},f1_0}; editor_view FrontView = {2,1, NULL, i2f(100),{{f1_0,0,0},{0,f1_0,0},{0,0,f1_0}},f1_0}; editor_view RightView = {3,1, NULL, i2f(100),{{0,0,f1_0},{0,f1_0,0},{f1_0,0,0}},f1_0}; #endif editor_view *Views[] = {&LargeView, #if ORTHO_VIEWS &TopView,&FrontView,&RightView #endif }; int N_views = (sizeof(Views) / sizeof(*Views)); int Lock_view_to_cursegp = 1; // !0 means whenever cursegp changes, view it int Num_tilings = 1; // Number of tilings per wall short Cur_object_index = -1; // The current object type and id short Cur_object_type = 4; // OBJ_PLAYER short Cur_object_id = 0; // !0 if a degenerate segment has been found. int Degenerate_segment_found=0; dxx-rebirth-0.58.1-d1x/editor/ehostage.c000066400000000000000000000301271217717257200200060ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for placing hostages, etc... * */ #include #include #include #include #include "screens.h" #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "timer.h" #include "objpage.h" #include "fix.h" #include "kdefs.h" #include "object.h" #include "polyobj.h" #include "game.h" #include "powerup.h" #include "ai.h" #include "hostage.h" #include "eobject.h" #include "medwall.h" #include "eswitch.h" #include "medrobot.h" #include "key.h" #include "bm.h" #include "sounds.h" #include "centers.h" #include "piggy.h" //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- static UI_DIALOG *MainWindow = NULL; static int CurrentHostageIndex = -1; static int LastHostageIndex = -1; typedef struct hostage_dialog { UI_GADGET_USERBOX *hostageViewBox; UI_GADGET_INPUTBOX *hostageText; UI_GADGET_BUTTON *quitButton; vclip *vclip_ptr; // Used for the vclip on monitor fix64 time; fix vclip_animation_time; // How long the rescue sequence has been playing fix vclip_playback_speed; // Calculated internally. Frames/second of vclip. } hostage_dialog; void vclip_play( hostage_dialog *h, vclip * vc, fix frame_time ) { int bitmapnum; if ( vc == NULL ) return; if ( vc != h->vclip_ptr ) { // Start new vclip h->vclip_ptr = vc; h->vclip_animation_time = 1; // Calculate the frame/second of the playback h->vclip_playback_speed = fixdiv(i2f(h->vclip_ptr->num_frames),h->vclip_ptr->play_time); } if ( h->vclip_animation_time <= 0 ) return; // Find next bitmap in the vclip bitmapnum = f2i(h->vclip_animation_time); // Check if vclip is done playing. if (bitmapnum >= h->vclip_ptr->num_frames) { h->vclip_animation_time = 1; // Restart this vclip bitmapnum = 0; } PIGGY_PAGE_IN( h->vclip_ptr->frames[bitmapnum] ); gr_bitmap(0,0,&GameBitmaps[h->vclip_ptr->frames[bitmapnum].index] ); h->vclip_animation_time += fixmul(frame_time, h->vclip_playback_speed ); } static char HostageMessage[] = " "; int SelectPrevHostage() { int start=0; do { CurrentHostageIndex--; if ( CurrentHostageIndex < 0 ) CurrentHostageIndex = MAX_HOSTAGES-1; start++; if ( start > MAX_HOSTAGES ) break; } while ( !hostage_is_valid( CurrentHostageIndex ) ); if (hostage_is_valid( CurrentHostageIndex ) ) { Cur_object_index = Hostages[CurrentHostageIndex].objnum; } else { CurrentHostageIndex =-1; } return CurrentHostageIndex; } int SelectNextHostage() { int start=0; do { CurrentHostageIndex++; if ( CurrentHostageIndex >= MAX_HOSTAGES ) CurrentHostageIndex = 0; start++; if ( start > MAX_HOSTAGES ) break; } while ( !hostage_is_valid( CurrentHostageIndex ) ); if (hostage_is_valid( CurrentHostageIndex ) ) { Cur_object_index = Hostages[CurrentHostageIndex].objnum; } else { CurrentHostageIndex =-1; } return CurrentHostageIndex; } int SelectClosestHostage() { int start=0; while ( !hostage_is_valid( CurrentHostageIndex ) ) { CurrentHostageIndex++; if ( CurrentHostageIndex >= MAX_HOSTAGES ) CurrentHostageIndex = 0; start++; if ( start > MAX_HOSTAGES ) break; } if (hostage_is_valid( CurrentHostageIndex ) ) { Cur_object_index = Hostages[CurrentHostageIndex].objnum; } else { CurrentHostageIndex =-1; } return CurrentHostageIndex; } int PlaceHostage() { int ctype,i; vms_vector cur_object_loc; //update_due_to_new_segment(); compute_segment_center(&cur_object_loc, Cursegp); ctype = -1; for (i=0; i= N_hostage_types ) //@@ Hostages[CurrentHostageIndex].type = 0; //@@ //@@ return 1; //@@} //@@ //@@int SelectNextVclip() { //@@ if (!hostage_is_valid( CurrentHostageIndex ) ) //@@ return 0; //@@ //@@ Hostages[CurrentHostageIndex].type++; //@@ if ( Hostages[CurrentHostageIndex].type >= N_hostage_types ) //@@ Hostages[CurrentHostageIndex].type = 0; //@@ //@@ return 1; //@@} //@@int find_next_hostage_sound() { //@@ int start=0,n; //@@ //@@ n = Hostages[CurrentHostageIndex].sound_num; //@@ do { //@@ n++; //@@ if ( n < SOUND_HOSTAGE_VOICES ) n = SOUND_HOSTAGE_VOICES+MAX_HOSTAGE_SOUNDS-1; //@@ if ( n >= SOUND_HOSTAGE_VOICES+MAX_HOSTAGE_SOUNDS ) n = SOUND_HOSTAGE_VOICES; //@@ start++; //@@ if ( start > MAX_HOSTAGE_SOUNDS ) break; //@@ } while ( Sounds[n] == NULL ); //@@ //@@ if ( Sounds[n] == NULL ) //@@ Hostages[CurrentHostageIndex].sound_num = -1; //@@ else { //@@ Hostages[CurrentHostageIndex].sound_num = n; //@@ PlayHostageSound(); //@@ } //@@ return 1; //@@} //@@ //@@int find_prev_hostage_sound() { //@@ int start=0,n; //@@ //@@ n = Hostages[CurrentHostageIndex].sound_num; //@@ do { //@@ n--; //@@ if ( n < SOUND_HOSTAGE_VOICES ) n = SOUND_HOSTAGE_VOICES+MAX_HOSTAGE_SOUNDS-1; //@@ if ( n >= SOUND_HOSTAGE_VOICES+MAX_HOSTAGE_SOUNDS ) n = SOUND_HOSTAGE_VOICES; //@@ start++; //@@ if ( start > MAX_HOSTAGE_SOUNDS ) break; //@@ } while ( Sounds[n] == NULL ); //@@ //@@ if ( Sounds[n] == NULL ) //@@ Hostages[CurrentHostageIndex].sound_num = -1; //@@ else { //@@ Hostages[CurrentHostageIndex].sound_num = n; //@@ PlayHostageSound(); //@@ } //@@ return 1; //@@} int hostage_dialog_handler(UI_DIALOG *dlg, d_event *event, hostage_dialog *h); //------------------------------------------------------------------------- // Called from the editor... does one instance of the hostage dialog box //------------------------------------------------------------------------- int do_hostage_dialog() { int i; hostage_dialog *h; // Only open 1 instance of this window... if ( MainWindow != NULL ) return 0; // Close other windows close_all_windows(); MALLOC(h, hostage_dialog, 1); if (!h) return 0; h->vclip_animation_time = 0; h->vclip_playback_speed = 0; h->vclip_ptr = NULL; CurrentHostageIndex = 0; SelectClosestHostage(); // Open a window with a quit button MainWindow = ui_create_dialog( TMAPBOX_X+10, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, (int (*)(UI_DIALOG *, d_event *, void *))hostage_dialog_handler, h ); h->quitButton = ui_add_gadget_button( MainWindow, 20, 222, 48, 40, "Done", NULL ); h->hostageText = ui_add_gadget_inputbox( MainWindow, 10, 50, HOSTAGE_MESSAGE_LEN, HOSTAGE_MESSAGE_LEN, HostageMessage ); // The little box the hostage vclip will play in. h->hostageViewBox = ui_add_gadget_userbox( MainWindow,10, 90+10, 64, 64 ); // A bunch of buttons... i = 90; //@@ ui_add_gadget_button( MainWindow,155,i,70, 26, "<< Type", SelectPrevVclip ); //@@ ui_add_gadget_button( MainWindow,155+70,i,70, 26, "Type >>", SelectNextVclip );i += 29; //@@ ui_add_gadget_button( MainWindow,155,i,70, 26, "<< Sound", find_prev_hostage_sound ); //@@ ui_add_gadget_button( MainWindow,155+70,i,70, 26, "Sound >>", find_next_hostage_sound );i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Next Hostage", SelectNextHostage ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Prev Hostage", SelectPrevHostage ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Compress All", CompressHostages ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Delete", ObjectDelete ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Create New", PlaceHostage ); i += 29; h->time = timer_query(); LastHostageIndex = -2; // Set to some dummy value so everything works ok on the first frame. // if ( CurrentHostageIndex == -1 ) // SelectNextHostage(); return 1; } void hostage_close_window() { if ( MainWindow!=NULL ) { ui_close_dialog( MainWindow ); MainWindow = NULL; } } int hostage_dialog_handler(UI_DIALOG *dlg, d_event *event, hostage_dialog *h) { fix64 Temp; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); Assert(MainWindow != NULL); SelectClosestHostage(); //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; //------------------------------------------------------------ // If we change objects, we need to reset the ui code for all // of the radio buttons that control the ai mode. Also makes // the current AI mode button be flagged as pressed down. //------------------------------------------------------------ if (LastHostageIndex != CurrentHostageIndex ) { strcpy(h->hostageText->text, " " ); h->hostageText->position = strlen(h->hostageText->text); h->hostageText->oldposition = h->hostageText->position; h->hostageText->status=1; h->hostageText->first_time = 1; } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the cooresponding AI state. //------------------------------------------------------------ //------------------------------------------------------------ // Redraw the object in the little 64x64 box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { ui_dprintf_at( MainWindow, 10, 32,"&Message:" ); // A simple frame time counter for spinning the objects... Temp = timer_query(); h->time = Temp; if (CurrentHostageIndex > -1 ) { gr_set_current_canvas( h->hostageViewBox->canvas ); gr_clear_canvas( CGREY ); } else { // no hostage, so just blank out gr_set_current_canvas( h->hostageViewBox->canvas ); gr_clear_canvas( CGREY ); } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { if ( CurrentHostageIndex > -1 ) { ui_dprintf_at( MainWindow, 10, 15, "Hostage: %d Object: %d", CurrentHostageIndex, Hostages[CurrentHostageIndex].objnum ); //@@ui_dprintf_at( MainWindow, 10, 73, "Type: %d Sound: %d ", Hostages[CurrentHostageIndex].type, Hostages[CurrentHostageIndex].sound_num ); } else { ui_dprintf_at( MainWindow, 10, 15, "Hostage: none " ); //@@ui_dprintf_at( MainWindow, 10, 73, "Type: Sound: " ); ui_dprintf_at( MainWindow, 10, 73, "Face: " ); } } if (ui_button_any_drawn || (LastHostageIndex != CurrentHostageIndex)) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(h); return 0; } if ( GADGET_PRESSED(h->quitButton) || (keypress==KEY_ESC)) { hostage_close_window(); return 1; } LastHostageIndex = CurrentHostageIndex; return rval; } dxx-rebirth-0.58.1-d1x/editor/elight.c000066400000000000000000000214601217717257200174630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Editor lighting functions. * */ #include #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "seguvs.h" #include "wall.h" #include "textures.h" #include "fix.h" #include "dxxerror.h" #include "kdefs.h" #include "gameseg.h" #include "texmap.h" // ----------------------------------------------------------------------------- // Return light intensity at an instance of a vertex on a side in a segment. fix get_light_intensity(segment *segp, int sidenum, int vert) { Assert(sidenum <= MAX_SIDES_PER_SEGMENT); Assert(vert <= 3); return segp->sides[sidenum].uvls[vert].l; } // ----------------------------------------------------------------------------- // Set light intensity at a vertex, saturating in .5 to 15.5 void set_light_intensity(segment *segp, int sidenum, int vert, fix intensity) { Assert(sidenum <= MAX_SIDES_PER_SEGMENT); Assert(vert <= 3); if (intensity < MIN_LIGHTING_VALUE) intensity = MIN_LIGHTING_VALUE; if (intensity > MAX_LIGHTING_VALUE) intensity = MAX_LIGHTING_VALUE; segp->sides[sidenum].uvls[vert].l = intensity; Update_flags |= UF_WORLD_CHANGED; } // ----------------------------------------------------------------------------- // Add light intensity to a vertex, saturating in .5 to 15.5 void add_light_intensity(segment *segp, int sidenum, int vert, fix intensity) { // fix new_intensity; set_light_intensity(segp, sidenum, vert, segp->sides[sidenum].uvls[vert].l + intensity); } // ----------------------------------------------------------------------------- // Recursively apply light to segments. // If current side is a wall, apply light there. // If not a wall, apply light to child through that wall. // Notes: // It is possible to enter a segment twice by taking different paths. It is easy // to prevent this by maintaining a list of visited segments, but it is important // to reach segments with the greatest light intensity. This can be done by doing // a breadth-first-search, or by storing the applied intensity with a visited segment, // and if the current intensity is brighter, then apply the difference between it and // the previous intensity. // Note that it is also possible to visit the original light-casting segment, for example // going from segment 0 to 2, then from 2 to 0. This is peculiar and probably not // desired, but not entirely invalid. 2 reflects some light back to 0. void apply_light_intensity(segment *segp, int sidenum, fix intensity, int depth) { int wid_result; if (intensity == 0) return; wid_result = WALL_IS_DOORWAY(segp, sidenum); if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) { int v; for (v=0; v<4; v++) // add light to this wall add_light_intensity(segp, sidenum, v, intensity); return; // we return because there is a wall here, and light does not shine through walls } // No wall here, so apply light recursively if (depth < 3) { int s; for (s=0; schildren[sidenum]], s, intensity/3, depth+1); } } // ----------------------------------------------------------------------------- // Top level recursive function for applying light. // Calls apply_light_intensity. // Uses light value on segp:sidenum (tmap_num2 defines light value) and applies // the associated intensity to segp. It calls apply_light_intensity to apply intensity/3 // to all neighbors. apply_light_intensity recursively calls itself to apply light to // subsequent neighbors (and forming loops, see above). void propagate_light_intensity(segment *segp, int sidenum) { int v,s; fix intensity; short texmap; intensity = 0; texmap = segp->sides[sidenum].tmap_num; intensity += TmapInfo[texmap].lighting; texmap = (segp->sides[sidenum].tmap_num2) & 0x3fff; intensity += TmapInfo[texmap].lighting; if (intensity > 0) { for (v=0; v<4; v++) add_light_intensity(segp, sidenum, v, intensity); // Now, for all sides which are not the same as sidenum (the side casting the light), // add a light value to them (if they have no children, ie, they have a wall there). for (s=0; s= 4) Curvert = 0; Update_flags |= UF_WORLD_CHANGED; return 1; } // ----------------------------------------------------------------------------- int LightSelectNextEdge(void) { Curedge++; if (Curedge >= 4) Curedge = 0; Update_flags |= UF_WORLD_CHANGED; return 1; } // ----------------------------------------------------------------------------- // Copy intensity from current vertex to all other vertices on side. int LightCopyIntensity(void) { int v,intensity; intensity = get_light_intensity(Cursegp, Curside, Curvert); for (v=0; v<4; v++) if (v != Curvert) set_light_intensity(Cursegp, Curside, v, intensity); return 1; } // ----------------------------------------------------------------------------- // Copy intensity from current vertex to all other vertices on side. int LightCopyIntensitySegment(void) { int s,v,intensity; intensity = get_light_intensity(Cursegp, Curside, Curvert); for (s=0; s #include #include #include #include #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "objpage.h" #include "fix.h" #include "dxxerror.h" #include "kdefs.h" #include "object.h" #include "polyobj.h" #include "game.h" #include "ai.h" #include "bm.h" #include "3d.h" // For g3_point_to_vec #include "fvi.h" #include "powerup.h" #include "fuelcen.h" #include "hostage.h" #include "medrobot.h" #include "player.h" #include "gameseg.h" #include "cntrlcen.h" #define OBJ_SCALE (F1_0/2) #define OBJ_DEL_SIZE (F1_0/2) #define ROTATION_UNIT (4096/4) //segment *Cur_object_seg = -1; void show_objects_in_segment(segment *sp) { short objid; objid = sp->objects; while (objid != -1) { objid = Objects[objid].next; } } //returns the number of the first object in a segment, skipping the player int get_first_object(segment *seg) { int id; id = seg->objects; if (id == (ConsoleObject-Objects)) id = Objects[id].next; return id; } //returns the number of the next object in a segment, skipping the player int get_next_object(segment *seg,int id) { if (id==-1 || (id=Objects[id].next)==-1) return get_first_object(seg); if (id == (ConsoleObject-Objects)) return get_next_object(seg,id); return id; } //@@// ------------------------------------------------------------------------------------------------------ //@@// this should be called whenever the current segment may have changed //@@// If Cur_object_seg != Cursegp, then update various variables. //@@// this used to be called update_due_to_new_segment() //@@void ObjectUpdateCurrent(void) //@@{ //@@ if (Cur_object_seg != Cursegp) { //@@ Cur_object_seg = Cursegp; //@@ Cur_object_index = get_first_object(Cur_object_seg); //@@ Update_flags |= UF_WORLD_CHANGED; //@@ } //@@ //@@} // ------------------------------------------------------------------------------------ int place_object(segment *segp, vms_vector *object_pos, short object_type, short object_id) { short objnum=0; object *obj; vms_matrix seg_matrix; med_extract_matrix_from_segment(segp,&seg_matrix); switch (object_type) { case OBJ_HOSTAGE: objnum = obj_create(OBJ_HOSTAGE, -1, segp-Segments,object_pos,&seg_matrix,HOSTAGE_SIZE, CT_NONE,MT_NONE,RT_HOSTAGE); if ( objnum < 0 ) return 0; obj = &Objects[objnum]; // Fill in obj->id and other hostage info hostage_init_info( objnum ); obj->control_type = CT_POWERUP; obj->rtype.vclip_info.vclip_num = Hostage_vclip_num[object_id]; obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time; obj->rtype.vclip_info.framenum = 0; break; case OBJ_ROBOT: objnum = obj_create(OBJ_ROBOT, object_id, segp - Segments, object_pos, &seg_matrix, Polygon_models[Robot_info[object_id].model_num].rad, CT_AI, MT_PHYSICS, RT_POLYOBJ); if ( objnum < 0 ) return 0; obj = &Objects[objnum]; //Set polygon-object-specific data obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; //set Physics info obj->mtype.phys_info.mass = Robot_info[obj->id].mass; obj->mtype.phys_info.drag = Robot_info[obj->id].drag; obj->mtype.phys_info.flags |= (PF_LEVELLING); obj->shields = Robot_info[obj->id].strength; { int hide_segment; if (Markedsegp) hide_segment = Markedsegp-Segments; else hide_segment = -1; // robots which lunge forward to attack cannot have behavior type still. if (Robot_info[obj->id].attack_type) init_ai_object(obj-Objects, AIB_NORMAL, hide_segment); else init_ai_object(obj-Objects, AIB_STILL, hide_segment); } break; case OBJ_POWERUP: objnum = obj_create(OBJ_POWERUP, object_id, segp - Segments, object_pos, &seg_matrix, Powerup_info[object_id].size, CT_POWERUP, MT_NONE, RT_POWERUP); if ( objnum < 0 ) return 0; obj = &Objects[objnum]; //set powerup-specific data obj->rtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num; obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].play_time/Vclip[obj->rtype.vclip_info.vclip_num].num_frames; obj->rtype.vclip_info.framenum = 0; if (obj->id == POW_VULCAN_WEAPON) obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT; else obj->ctype.powerup_info.count = 1; break; case OBJ_CNTRLCEN: { objnum = obj_create(OBJ_CNTRLCEN, object_id, segp - Segments, object_pos, &seg_matrix, Polygon_models[object_id].rad, CT_CNTRLCEN, MT_NONE, RT_POLYOBJ); if ( objnum < 0 ) return 0; obj = &Objects[objnum]; //Set polygon-object-specific data obj->shields = 0; // stored in Reactor_strength or calculated obj->rtype.pobj_info.model_num = ObjId[object_type]; obj->rtype.pobj_info.subobj_flags = 0; break; } case OBJ_PLAYER: { objnum = obj_create(OBJ_PLAYER, object_id, segp - Segments, object_pos, &seg_matrix, Polygon_models[Player_ship->model_num].rad, CT_NONE, MT_PHYSICS, RT_POLYOBJ); if ( objnum < 0 ) return 0; obj = &Objects[objnum]; //Set polygon-object-specific data obj->rtype.pobj_info.model_num = Player_ship->model_num; obj->rtype.pobj_info.subobj_flags = 0; //for (i=0;irtype.pobj_info.anim_angles[i]); //set Physics info vm_vec_zero(&obj->mtype.phys_info.velocity); obj->mtype.phys_info.mass = Player_ship->mass; obj->mtype.phys_info.drag = Player_ship->drag; obj->mtype.phys_info.flags |= PF_TURNROLL | PF_LEVELLING | PF_WIGGLE; obj->shields = i2f(100); break; } default: break; } Cur_object_index = objnum; //Cur_object_seg = Cursegp; show_objects_in_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ // Count number of player objects, return value. int compute_num_players(void) { int i, count = 0; for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_PLAYER) count++; return count; } int ObjectMakeCoop(void) { Assert(Cur_object_index != -1); Assert(Cur_object_index < MAX_OBJECTS); // Assert(Objects[Cur_object_index.type == OBJ_PLAYER); if (Objects[Cur_object_index].type == OBJ_PLAYER ) { Objects[Cur_object_index].type = OBJ_COOP; editor_status("You just made a player object COOPERATIVE"); } else editor_status("This is not a player object"); return 1; } // ------------------------------------------------------------------------------------------------------ // Place current object at center of current segment. int ObjectPlaceObject(void) { int old_cur_object_index; int rval; vms_vector cur_object_loc; #ifdef SHAREWARE if (Cur_object_type == OBJ_PLAYER) { int num_players = compute_num_players(); Assert(num_players <= MAX_PLAYERS); if (num_players == MAX_PLAYERS) { editor_status("Can't place player object. Already %i players.", MAX_PLAYERS); return -1; } } #endif #ifndef SHAREWARE if (Cur_object_type == OBJ_PLAYER) { int num_players = compute_num_players(); Assert(num_players <= MAX_MULTI_PLAYERS); if (num_players > MAX_PLAYERS) editor_status("You just placed a cooperative player object"); if (num_players == MAX_MULTI_PLAYERS) { editor_status_fmt("Can't place player object. Already %i players.", MAX_MULTI_PLAYERS); return -1; } } #endif //update_due_to_new_segment(); compute_segment_center(&cur_object_loc, Cursegp); old_cur_object_index = Cur_object_index; rval = place_object(Cursegp, &cur_object_loc, Cur_object_type, Cur_object_id); if (old_cur_object_index != Cur_object_index) Objects[Cur_object_index].rtype.pobj_info.tmap_override = -1; return rval; } // ------------------------------------------------------------------------------------------------------ // Place current object at center of current segment. int ObjectPlaceObjectTmap(void) { int rval, old_cur_object_index; vms_vector cur_object_loc; //update_due_to_new_segment(); compute_segment_center(&cur_object_loc, Cursegp); old_cur_object_index = Cur_object_index; rval = place_object(Cursegp, &cur_object_loc, Cur_object_type, Cur_object_id); if ((Cur_object_index != old_cur_object_index) && (Objects[Cur_object_index].render_type == RT_POLYOBJ)) Objects[Cur_object_index].rtype.pobj_info.tmap_override = CurrentTexture; else editor_status("Unable to apply current texture map to this object."); return rval; } // ------------------------------------------------------------------------------------------------------ int ObjectSelectNextinSegment(void) { int id; segment *objsegp; //update_due_to_new_segment(); //Assert(Cur_object_seg == Cursegp); if (Cur_object_index == -1) { objsegp = Cursegp; Cur_object_index = objsegp->objects; } else { objsegp = Cursegp; if (Objects[Cur_object_index].segnum != Cursegp-Segments) Cur_object_index = objsegp->objects; } //Debug: make sure current object is in current segment for (id=objsegp->objects;(id != Cur_object_index) && (id != -1);id=Objects[id].next); Assert(id == Cur_object_index); //should have found object // Select the next object, wrapping back to start if we are at the end of the linked list for this segment. if (id != -1) Cur_object_index = get_next_object(objsegp,Cur_object_index); Update_flags |= UF_WORLD_CHANGED; return 1; } //Moves to next object in the mine, skipping the player int ObjectSelectNextInMine() { int i; for (i=0;i= MAX_OBJECTS ) Cur_object_index= 0; if ((Objects[Cur_object_index ].type != OBJ_NONE) && (Cur_object_index != (ConsoleObject-Objects)) ) { Cursegp = &Segments[Objects[Cur_object_index ].segnum]; med_create_new_segment_from_cursegp(); //Cur_object_seg = Cursegp; return 1; } } Cur_object_index = -1; Update_flags |= UF_WORLD_CHANGED; return 0; } //Moves to next object in the mine, skipping the player int ObjectSelectPrevInMine() { int i; for (i=0;ipos, segnum, 0, __FILE__, __LINE__); if (result.centermask == 0) { int fate; fvi_info hit_info; fvi_query fq; // See if the radius pokes through any wall. fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = newpos; fq.rad = obj->size; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; fate = find_vector_intersection(&fq,&hit_info); if (fate != HIT_WALL) { if ( segnum != obj->segnum ) obj_relink( obj-Objects, segnum); obj->pos = *newpos; return 0; } } } return 1; } // Return 0 if object is in expected segment, else return 1 int verify_object_seg(object *objp, vms_vector *newpos) { segmasks result = get_seg_masks(newpos, objp->segnum, objp->size, __FILE__, __LINE__); if (result.facemask == 0) return 0; else return move_object_within_mine(objp, newpos); } // ------------------------------------------------------------------------------------------------------ int ObjectMoveForward(void) { object *obj; vms_vector fvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_forward_vector_from_segment(&Segments[obj->segnum], &fvec); vm_vec_normalize(&fvec); vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&fvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMoveBack(void) { object *obj; vms_vector fvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_forward_vector_from_segment(&Segments[obj->segnum], &fvec); vm_vec_normalize(&fvec); vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&fvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMoveLeft(void) { object *obj; vms_vector rvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_right_vector_from_segment(&Segments[obj->segnum], &rvec); vm_vec_normalize(&rvec); vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&rvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMoveRight(void) { object *obj; vms_vector rvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_right_vector_from_segment(&Segments[obj->segnum], &rvec); vm_vec_normalize(&rvec); vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&rvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectSetDefault(void) { //update_due_to_new_segment(); if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } compute_segment_center(&Objects[Cur_object_index].pos, &Segments[Objects[Cur_object_index].segnum]); Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMoveUp(void) { object *obj; vms_vector uvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_up_vector_from_segment(&Segments[obj->segnum], &uvec); vm_vec_normalize(&uvec); vm_vec_add(&newpos, &obj->pos, vm_vec_scale(&uvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMoveDown(void) { object *obj; vms_vector uvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_up_vector_from_segment(&Segments[obj->segnum], &uvec); vm_vec_normalize(&uvec); vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&uvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMakeSmaller(void) { fix cur_size; //update_due_to_new_segment(); cur_size = Objects[Cur_object_index].size; cur_size -= OBJ_DEL_SIZE; if (cur_size < OBJ_DEL_SIZE) cur_size = OBJ_DEL_SIZE; Objects[Cur_object_index].size = cur_size; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int ObjectMakeLarger(void) { fix cur_size; //update_due_to_new_segment(); cur_size = Objects[Cur_object_index].size; cur_size += OBJ_DEL_SIZE; Objects[Cur_object_index].size = cur_size; Update_flags |= UF_WORLD_CHANGED; return 1; } // ------------------------------------------------------------------------------------------------------ int rotate_object(short objnum, int p, int b, int h) { object *obj = &Objects[objnum]; vms_angvec ang; vms_matrix rotmat,tempm; // vm_extract_angles_matrix( &ang,&obj->orient); // ang.p += p; // ang.b += b; // ang.h += h; ang.p = p; ang.b = b; ang.h = h; vm_angles_2_matrix(&rotmat, &ang); vm_matrix_x_matrix(&tempm, &obj->orient, &rotmat); obj->orient = tempm; // vm_angles_2_matrix(&obj->orient, &ang); Update_flags |= UF_WORLD_CHANGED; return 1; } void reset_object(short objnum) { object *obj = &Objects[objnum]; med_extract_matrix_from_segment(&Segments[obj->segnum],&obj->orient); } int ObjectResetObject() { reset_object(Cur_object_index); Update_flags |= UF_WORLD_CHANGED; return 1; } int ObjectFlipObject() { vms_matrix *m=&Objects[Cur_object_index].orient; vm_vec_negate(&m->uvec); vm_vec_negate(&m->rvec); Update_flags |= UF_WORLD_CHANGED; return 1; } int ObjectDecreaseBank() {return rotate_object(Cur_object_index, 0, -ROTATION_UNIT, 0);} int ObjectIncreaseBank() {return rotate_object(Cur_object_index, 0, ROTATION_UNIT, 0);} int ObjectDecreasePitch() {return rotate_object(Cur_object_index, -ROTATION_UNIT, 0, 0);} int ObjectIncreasePitch() {return rotate_object(Cur_object_index, ROTATION_UNIT, 0, 0);} int ObjectDecreaseHeading() {return rotate_object(Cur_object_index, 0, 0, -ROTATION_UNIT);} int ObjectIncreaseHeading() {return rotate_object(Cur_object_index, 0, 0, ROTATION_UNIT);} int ObjectDecreaseBankBig() {return rotate_object(Cur_object_index, 0, -(ROTATION_UNIT*4), 0);} int ObjectIncreaseBankBig() {return rotate_object(Cur_object_index, 0, (ROTATION_UNIT*4), 0);} int ObjectDecreasePitchBig() {return rotate_object(Cur_object_index, -(ROTATION_UNIT*4), 0, 0);} int ObjectIncreasePitchBig() {return rotate_object(Cur_object_index, (ROTATION_UNIT*4), 0, 0);} int ObjectDecreaseHeadingBig() {return rotate_object(Cur_object_index, 0, 0, -(ROTATION_UNIT*4));} int ObjectIncreaseHeadingBig() {return rotate_object(Cur_object_index, 0, 0, (ROTATION_UNIT*4));} // ----------------------------------------------------------------------------------------------------- // Move object around based on clicks in 2d screen. // Slide an object parallel to the 2d screen, to a point on a vector. // The vector is defined by a point on the 2d screen and the eye. // V = vector from eye to 2d screen point. // E = eye // F = forward vector from eye // O = 3-space location of object // D = depth of object given forward vector F // = (OE dot norm(F)) // Must solve intersection of: // E + tV ( equation of vector from eye through point on 2d screen) // Fs + D ( equation of plane parallel to 2d screen, at depth D) // = Fx(Ex + tVx) + Fy(Ey + tVy) + Fz(Ez + tVz) + D = 0 // // FxEx + FyEy + FzEz - D // t = - ---------------------- // VxFx + VyFy + VzFz void move_object_to_position(int objnum, vms_vector *newpos) { object *objp = &Objects[objnum]; segmasks result = get_seg_masks(newpos, objp->segnum, objp->size, __FILE__, __LINE__); if (result.facemask == 0) { objp->pos = *newpos; } else { if (verify_object_seg(&Objects[objnum], newpos)) { int fate, count; int viewer_segnum; object temp_viewer_obj; fvi_query fq; fvi_info hit_info; vms_vector last_outside_pos; temp_viewer_obj = *Viewer; viewer_segnum = find_object_seg(&temp_viewer_obj); temp_viewer_obj.segnum = viewer_segnum; // If the viewer is outside the mine, get him in the mine! if (viewer_segnum == -1) { // While outside mine, move towards object count = 0; while (viewer_segnum == -1) { vms_vector temp_vec; last_outside_pos = temp_viewer_obj.pos; vm_vec_avg(&temp_vec, &temp_viewer_obj.pos, newpos); temp_viewer_obj.pos = temp_vec; viewer_segnum = find_object_seg(&temp_viewer_obj); temp_viewer_obj.segnum = viewer_segnum; if (count > 5) { editor_status("Unable to move object, can't get viewer in mine. Aborting"); return; } } count = 0; // While inside mine, move away from object. while (viewer_segnum != -1) { vms_vector temp_vec; vm_vec_avg(&temp_vec, &temp_viewer_obj.pos, &last_outside_pos); temp_viewer_obj.pos = temp_vec; update_object_seg(&temp_viewer_obj); viewer_segnum = find_object_seg(&temp_viewer_obj); temp_viewer_obj.segnum = viewer_segnum; if (count > 5) { editor_status("Unable to move object, can't get viewer back out of mine. Aborting"); return; } } } fq.p0 = &temp_viewer_obj.pos; fq.startseg = temp_viewer_obj.segnum; fq.p1 = newpos; fq.rad = temp_viewer_obj.size; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; fate = find_vector_intersection(&fq,&hit_info); if (fate == HIT_WALL) { int new_segnum; objp->pos = hit_info.hit_pnt; new_segnum = find_object_seg(objp); Assert(new_segnum != -1); obj_relink(objp-Objects, new_segnum); } else { editor_status("Attempted to move object out of mine. Object not moved."); } } } Update_flags |= UF_WORLD_CHANGED; } void move_object_to_vector(vms_vector *vec_through_screen, fix delta_distance) { vms_vector result; vm_vec_scale_add(&result, &Viewer->pos, vec_through_screen, vm_vec_dist(&Viewer->pos,&Objects[Cur_object_index].pos)+delta_distance); move_object_to_position(Cur_object_index, &result); } void move_object_to_mouse_click_delta(fix delta_distance) { short xcrd,ycrd; vms_vector vec_through_screen; if (Cur_object_index == -1) { editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!"); return; } xcrd = GameViewBox->b1_drag_x1; ycrd = GameViewBox->b1_drag_y1; med_point_2_vec(&_canv_editor_game, &vec_through_screen, xcrd, ycrd); move_object_to_vector(&vec_through_screen, delta_distance); } void move_object_to_mouse_click(void) { move_object_to_mouse_click_delta(0); } int ObjectMoveNearer(void) { vms_vector result; if (Cur_object_index == -1) { editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!"); return 1; } // move_object_to_mouse_click_delta(-4*F1_0); // Move four units closer to eye vm_vec_sub(&result, &Objects[Cur_object_index].pos, &Viewer->pos); vm_vec_normalize(&result); move_object_to_vector(&result, -4*F1_0); return 1; } int ObjectMoveFurther(void) { vms_vector result; if (Cur_object_index == -1) { editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!"); return 1; } // move_object_to_mouse_click_delta(+4*F1_0); // Move four units further from eye vm_vec_sub(&result, &Objects[Cur_object_index].pos, &Viewer->pos); vm_vec_normalize(&result); move_object_to_vector(&result, 4*F1_0); return 1; } dxx-rebirth-0.58.1-d1x/editor/eswitch.c000066400000000000000000000354111217717257200176560ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Editor switch functions. * */ #include #include #include #include #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "eswitch.h" #include "segment.h" #include "dxxerror.h" #include "gameseg.h" #include "wall.h" #include "medwall.h" #include "screens.h" #include "textures.h" #include "texmerge.h" #include "medrobot.h" #include "timer.h" #include "key.h" #include "ehostage.h" #include "centers.h" #include "piggy.h" //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- #define NUM_TRIGGER_FLAGS 10 static UI_DIALOG *MainWindow = NULL; typedef struct trigger_dialog { UI_GADGET_USERBOX *wallViewBox; UI_GADGET_BUTTON *quitButton; UI_GADGET_CHECKBOX *triggerFlag[NUM_TRIGGER_FLAGS]; int old_trigger_num; } trigger_dialog; //----------------------------------------------------------------- // Adds a trigger to wall, and returns the trigger number. // If there is a trigger already present, it returns the trigger number. (To be replaced) int add_trigger(segment *seg, short side) { int trigger_num = Num_triggers; int wall_num = seg->sides[side].wall_num; Assert(trigger_num < MAX_TRIGGERS); if (trigger_num>=MAX_TRIGGERS) return -1; if (wall_num == -1) { wall_add_to_markedside(WALL_OPEN); wall_num = seg->sides[side].wall_num; Walls[wall_num].trigger = trigger_num; // Set default values first time trigger is added Triggers[trigger_num].flags = 0; Triggers[trigger_num].value = F1_0*5; Triggers[trigger_num].num_links = 0; Triggers[trigger_num].flags &= TRIGGER_ON; Num_triggers++; return trigger_num; } else { if (Walls[wall_num].trigger != -1) return Walls[wall_num].trigger; // Create new trigger. Walls[wall_num].trigger = trigger_num; // Set default values first time trigger is added Triggers[trigger_num].flags = 0; Triggers[trigger_num].value = F1_0*5; Triggers[trigger_num].num_links = 0; Triggers[trigger_num].flags &= TRIGGER_ON; Num_triggers++; return trigger_num; } } //----------------------------------------------------------------- // Adds a specific trigger flag to Markedsegp/Markedside if it is possible. // Automatically adds flag to Connectside if possible unless it is a control trigger. // Returns 1 if trigger flag added. // Returns 0 if trigger flag cannot be added. int trigger_flag_Markedside(short flag, int value) { int trigger_num; //, ctrigger_num; int wall_num; if (!Markedsegp) { editor_status("No Markedside."); return 0; } // If no child on Markedside return if (!IS_CHILD(Markedsegp->children[Markedside])) return 0; // If no wall just return wall_num = Markedsegp->sides[Markedside].wall_num; if (!value && wall_num == -1) return 0; trigger_num = value ? add_trigger(Markedsegp, Markedside) : Walls[wall_num].trigger; if (trigger_num == -1) { editor_status(value ? "Cannot add trigger at Markedside." : "No trigger at Markedside."); return 0; } if (value) Triggers[trigger_num].flags |= flag; else Triggers[trigger_num].flags &= ~flag; return 1; } int bind_matcen_to_trigger() { int wall_num, trigger_num, link_num; int i; if (!Markedsegp) { editor_status("No marked segment."); return 0; } wall_num = Markedsegp->sides[Markedside].wall_num; if (wall_num == -1) { editor_status("No wall at Markedside."); return 0; } trigger_num = Walls[wall_num].trigger; if (trigger_num == -1) { editor_status("No trigger at Markedside."); return 0; } if (!(Cursegp->special & SEGMENT_IS_ROBOTMAKER)) { editor_status("No Matcen at Cursegp."); return 0; } link_num = Triggers[trigger_num].num_links; for (i=0;isides[Markedside].wall_num; if (wall_num == -1) { editor_status("No wall at Markedside."); return 0; } trigger_num = Walls[wall_num].trigger; if (trigger_num == -1) { editor_status("No trigger at Markedside."); return 0; } if (Cursegp->sides[Curside].wall_num == -1) { editor_status("No wall at Curside."); return 0; } if ((Cursegp==Markedsegp) && (Curside==Markedside)) { editor_status("Cannot bind wall to itself."); return 0; } link_num = Triggers[trigger_num].num_links; for (i=0;i trigger_num) Walls[w].trigger--; } return 1; } editor_status("No trigger to remove"); return 0; } int remove_trigger(segment *seg, short side) { if (seg->sides[side].wall_num == -1) { return 0; } return remove_trigger_num(Walls[seg->sides[side].wall_num].trigger); } int add_trigger_control() { trigger_flag_Markedside(TRIGGER_CONTROL_DOORS, 1); Update_flags = UF_WORLD_CHANGED; return 1; } int trigger_remove() { remove_trigger(Markedsegp, Markedside); Update_flags = UF_WORLD_CHANGED; return 1; } int trigger_turn_all_ON() { int t; for (t=0;ttriggerFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Door Control" ); i+=22; t->triggerFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Shield damage" ); i+=22; t->triggerFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Energy drain" ); i+=22; t->triggerFlag[3] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Exit" ); i+=22; t->triggerFlag[4] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "One-shot" ); i+=22; t->triggerFlag[5] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion ON" ); i+=22; t->triggerFlag[6] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i+=22; t->triggerFlag[7] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Trigger ON" ); i+=22; t->triggerFlag[8] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Matcen Trigger" ); i+=22; t->triggerFlag[9] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Secret Exit" ); i+=22; t->quitButton = ui_add_gadget_button( MainWindow, 20, i, 48, 40, "Done", NULL ); // The little box the wall will appear in. t->wallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 ); // A bunch of buttons... i = 80; // ui_add_gadget_button( MainWindow,155,i,140, 26, "Add Door Control", add_trigger_control ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Remove Trigger", trigger_remove ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Bind Wall", bind_wall_to_trigger ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "Bind Matcen", bind_matcen_to_trigger ); i += 29; ui_add_gadget_button( MainWindow,155,i,140, 26, "All Triggers ON", trigger_turn_all_ON ); i += 29; t->old_trigger_num = -2; // Set to some dummy value so everything works ok on the first frame. return 1; } void close_trigger_window() { if ( MainWindow!=NULL ) { ui_close_dialog( MainWindow ); MainWindow = NULL; } } int trigger_dialog_handler(UI_DIALOG *dlg, d_event *event, trigger_dialog *t) { int i; short Markedwall, trigger_num; int keypress = 0; int rval = 0; Assert(MainWindow != NULL); if (!Markedsegp) { close_trigger_window(); return 0; } //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); //------------------------------------------------------------ // If we change walls, we need to reset the ui code for all // of the checkboxes that control the wall flags. //------------------------------------------------------------ Markedwall = Markedsegp->sides[Markedside].wall_num; if (Markedwall != -1) trigger_num = Walls[Markedwall].trigger; else trigger_num = -1; if (t->old_trigger_num != trigger_num) { if (trigger_num != -1) { trigger *trig = &Triggers[trigger_num]; ui_checkbox_check(t->triggerFlag[0], trig->flags & TRIGGER_CONTROL_DOORS); ui_checkbox_check(t->triggerFlag[1], trig->flags & TRIGGER_SHIELD_DAMAGE); ui_checkbox_check(t->triggerFlag[2], trig->flags & TRIGGER_ENERGY_DRAIN); ui_checkbox_check(t->triggerFlag[3], trig->flags & TRIGGER_EXIT); ui_checkbox_check(t->triggerFlag[4], trig->flags & TRIGGER_ONE_SHOT); ui_checkbox_check(t->triggerFlag[5], trig->flags & TRIGGER_ILLUSION_ON); ui_checkbox_check(t->triggerFlag[6], trig->flags & TRIGGER_ILLUSION_OFF); ui_checkbox_check(t->triggerFlag[7], trig->flags & TRIGGER_ON); ui_checkbox_check(t->triggerFlag[8], trig->flags & TRIGGER_MATCEN); ui_checkbox_check(t->triggerFlag[9], trig->flags & TRIGGER_SECRET_EXIT); } } //------------------------------------------------------------ // If any of the checkboxes that control the wallflags are set, then // update the cooresponding wall flag. //------------------------------------------------------------ if (IS_CHILD(Markedsegp->children[Markedside])) { rval = 1; if (GADGET_PRESSED(t->triggerFlag[0])) trigger_flag_Markedside(TRIGGER_CONTROL_DOORS, t->triggerFlag[0]->flag); else if (GADGET_PRESSED(t->triggerFlag[1])) trigger_flag_Markedside(TRIGGER_SHIELD_DAMAGE, t->triggerFlag[1]->flag); else if (GADGET_PRESSED(t->triggerFlag[2])) trigger_flag_Markedside(TRIGGER_ENERGY_DRAIN, t->triggerFlag[2]->flag); else if (GADGET_PRESSED(t->triggerFlag[3])) trigger_flag_Markedside(TRIGGER_EXIT, t->triggerFlag[3]->flag); else if (GADGET_PRESSED(t->triggerFlag[4])) trigger_flag_Markedside(TRIGGER_ONE_SHOT, t->triggerFlag[4]->flag); else if (GADGET_PRESSED(t->triggerFlag[5])) trigger_flag_Markedside(TRIGGER_ILLUSION_ON, t->triggerFlag[5]->flag); else if (GADGET_PRESSED(t->triggerFlag[6])) trigger_flag_Markedside(TRIGGER_ILLUSION_OFF, t->triggerFlag[6]->flag); else if (GADGET_PRESSED(t->triggerFlag[7])) trigger_flag_Markedside(TRIGGER_ON, t->triggerFlag[7]->flag); else if (GADGET_PRESSED(t->triggerFlag[8])) trigger_flag_Markedside(TRIGGER_MATCEN, t->triggerFlag[8]->flag); else if (GADGET_PRESSED(t->triggerFlag[9])) trigger_flag_Markedside(TRIGGER_SECRET_EXIT, t->triggerFlag[9]->flag); else rval = 0; } else for (i = 0; i < NUM_TRIGGER_FLAGS; i++ ) ui_checkbox_check(t->triggerFlag[i], 0); //------------------------------------------------------------ // Draw the wall in the little 64x64 box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { gr_set_current_canvas( t->wallViewBox->canvas ); if ((Markedsegp->sides[Markedside].wall_num == -1) || (Walls[Markedsegp->sides[Markedside].wall_num].trigger) == -1) gr_clear_canvas( CBLACK ); else { if (Markedsegp->sides[Markedside].tmap_num2 > 0) { gr_ubitmap(0,0, texmerge_get_cached_bitmap( Markedsegp->sides[Markedside].tmap_num, Markedsegp->sides[Markedside].tmap_num2)); } else { if (Markedsegp->sides[Markedside].tmap_num > 0) { PIGGY_PAGE_IN(Textures[Markedsegp->sides[Markedside].tmap_num]); gr_ubitmap(0,0, &GameBitmaps[Textures[Markedsegp->sides[Markedside].tmap_num].index]); } else gr_clear_canvas( CGREY ); } } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { if ( Markedsegp->sides[Markedside].wall_num > -1 ) { ui_dprintf_at( MainWindow, 12, 6, "Trigger: %d ", trigger_num); } else { ui_dprintf_at( MainWindow, 12, 6, "Trigger: none "); } } if (ui_button_any_drawn || (t->old_trigger_num != trigger_num) ) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(t); MainWindow = NULL; return 0; } if ( GADGET_PRESSED(t->quitButton) || (keypress==KEY_ESC)) { close_trigger_window(); return 1; } t->old_trigger_num = trigger_num; return rval; } dxx-rebirth-0.58.1-d1x/editor/fixseg.c000066400000000000000000000143261217717257200174770ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to make faces planar and probably other things. * */ #include #include #include #include #include "key.h" #include "gr.h" #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "gameseg.h" #define SWAP(a,b) {temp = (a); (a) = (b); (b) = temp;} // ----------------------------------------------------------------------------------------------------------------- // Gauss-Jordan elimination solution of a system of linear equations. // a[1..n][1..n] is the input matrix. b[1..n][1..m] is input containing the m right-hand side vectors. // On output, a is replaced by its matrix inverse and b is replaced by the corresponding set of solution vectors. void gaussj(fix **a, int n, fix **b, int m) { int indxc[4], indxr[4], ipiv[4]; int i, icol=0, irow=0, j, k, l, ll; fix big, dum, pivinv, temp; if (n > 4) { Int3(); } for (j=1; j<=n; j++) ipiv[j] = 0; for (i=1; i<=n; i++) { big = 0; for (j=1; j<=n; j++) if (ipiv[j] != 1) for (k=1; k<=n; k++) { if (ipiv[k] == 0) { if (abs(a[j][k]) >= big) { big = abs(a[j][k]); irow = j; icol = k; } } else if (ipiv[k] > 1) { Int3(); } } ++(ipiv[icol]); // We now have the pivot element, so we interchange rows, if needed, to put the pivot // element on the diagonal. The columns are not physically interchanged, only relabeled: // indxc[i], the column of the ith pivot element, is the ith column that is reduced, while // indxr[i] is the row in which that pivot element was originally located. If indxr[i] != // indxc[i] there is an implied column interchange. With this form of bookkeeping, the // solution b's will end up in the correct order, and the inverse matrix will be scrambled // by columns. if (irow != icol) { for (l=1; l<=n; l++) SWAP(a[irow][l], a[icol][l]); for (l=1; l<=m; l++) SWAP(b[irow][l], b[icol][l]); } indxr[i] = irow; indxc[i] = icol; if (a[icol][icol] == 0) { Int3(); } pivinv = fixdiv(F1_0, a[icol][icol]); a[icol][icol] = F1_0; for (l=1; l<=n; l++) a[icol][l] = fixmul(a[icol][l], pivinv); for (l=1; l<=m; l++) b[icol][l] = fixmul(b[icol][l], pivinv); for (ll=1; ll<=n; ll++) if (ll != icol) { dum = a[ll][icol]; a[ll][icol] = 0; for (l=1; l<=n; l++) a[ll][l] -= a[icol][l]*dum; for (l=1; l<=m; l++) b[ll][l] -= b[icol][l]*dum; } } // This is the end of the main loop over columns of the reduction. It only remains to unscramble // the solution in view of the column interchanges. We do this by interchanging pairs of // columns in the reverse order that the permutation was built up. for (l=n; l>=1; l--) { if (indxr[l] != indxc[l]) for (k=1; k<=n; k++) SWAP(a[k][indxr[l]], a[k][indxc[l]]); } } // ----------------------------------------------------------------------------------------------------------------- // Return true if side is planar, else return false. int side_is_planar_p(segment *sp, int side) { sbyte *vp; vms_vector *v0,*v1,*v2,*v3; vms_vector va,vb; vp = Side_to_verts[side]; v0 = &Vertices[sp->verts[vp[0]]]; v1 = &Vertices[sp->verts[vp[1]]]; v2 = &Vertices[sp->verts[vp[2]]]; v3 = &Vertices[sp->verts[vp[3]]]; vm_vec_normalize(vm_vec_normal(&va,v0,v1,v2)); vm_vec_normalize(vm_vec_normal(&vb,v0,v2,v3)); // If the two vectors are very close to being the same, then generate one quad, else generate two triangles. return (vm_vec_dist(&va,&vb) < F1_0/1000); } // ------------------------------------------------------------------------------------------------- // Return coordinates of a vertex which is vertex v moved so that all sides of which it is a part become planar. void compute_planar_vert(segment *sp, int side, int v, vms_vector *vp) { if ((sp) && (side > -3)) *vp = Vertices[v]; } // ------------------------------------------------------------------------------------------------- // Making Cursegp:Curside planar. // If already planar, return. // for each vertex v on side, not part of another segment // choose the vertex v which can be moved to make all sides of which it is a part planar, minimizing distance moved // if there is no vertex v on side, not part of another segment, give up in disgust // Return value: // 0 curside made planar (or already was) // 1 did not make curside planar int make_curside_planar(void) { int v; sbyte *vp; vms_vector planar_verts[4]; // store coordinates of up to 4 vertices which will make Curside planar, corresponding to each of 4 vertices on side int present_verts[4]; // set to 1 if vertex is present if (side_is_planar_p(Cursegp, Curside)) return 0; // Look at all vertices in side to find a free one. for (v=0; v<4; v++) present_verts[v] = 0; vp = Side_to_verts[Curside]; for (v=0; v<4; v++) { int v1 = vp[v]; // absolute vertex id if (is_free_vertex(Cursegp->verts[v1])) { compute_planar_vert(Cursegp, Curside, Cursegp->verts[v1], &planar_verts[v]); present_verts[v] = 1; } } // Now, for each v for which present_verts[v] == 1, there is a vector (point) in planar_verts[v]. // See which one is closest to the plane defined by the other three points. // Nah...just use the first one we find. for (v=0; v<4; v++) if (present_verts[v]) { med_set_vertex(vp[v],&planar_verts[v]); validate_segment(Cursegp); // -- should propagate tmaps to segments or something here... return 0; } // We tried, but we failed, to make Curside planer. return 1; } dxx-rebirth-0.58.1-d1x/editor/func.c000066400000000000000000000040501217717257200171360ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * . * */ #include #include #include "func.h" #include "strutil.h" #define MAX_PARAMS 10 static FUNCTION * func_table = NULL; static int func_size = 0; static int initialized = 0; static int func_params[MAX_PARAMS]; int func_howmany() { return func_size; } void func_init( FUNCTION * funtable, int size ) { if (!initialized) { initialized = 1; func_table = funtable; func_size = size; atexit( func_close ); } } void func_close() { if (initialized) { initialized = 0; func_table = NULL; func_size = 0; } } int (*func_get( char * name, int * numparams ))(void) { int i; for (i=0; i #include #include "gr.h" #include "ui.h" #include "inferno.h" #include "segment.h" #include "editor/editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "gamemine.h" #include "gameseg.h" #include "bm.h" // For MAX_TEXTURES. #include "textures.h" #include "hash.h" #include "fuelcen.h" #include "medwall.h" void validate_selected_segments(void); struct { int fileinfo_version; int fileinfo_sizeof; } group_top_fileinfo; // Should be same as first two fields below... struct { int fileinfo_version; int fileinfo_sizeof; int header_offset; // Stuff common to game & editor int header_size; int editor_offset; // Editor specific stuff int editor_size; int vertex_offset; int vertex_howmany; int vertex_sizeof; int segment_offset; int segment_howmany; int segment_sizeof; int texture_offset; int texture_howmany; int texture_sizeof; } group_fileinfo; struct { int num_vertices; int num_segments; } group_header; struct { int current_seg; int newsegment_offset; int newsegment_size; int Groupsegp; int Groupside; } group_editor; group GroupList[MAX_GROUPS+1]; segment *Groupsegp[MAX_GROUPS+1]; int Groupside[MAX_GROUPS+1]; int Group_orientation[MAX_GROUPS+1]; int current_group=-1; int num_groups=0; // -- void swap_negate_columns(vms_matrix *rotmat, int col1, int col2) // -- { // -- fix col1_1,col1_2,col1_3; // -- fix col2_1,col2_2,col2_3; // -- // -- switch (col1) { // -- case 0: // -- col1_1 = rotmat->m1; // -- col1_2 = rotmat->m2; // -- col1_3 = rotmat->m3; // -- break; // -- // -- case 1: // -- col1_1 = rotmat->m4; // -- col1_2 = rotmat->m5; // -- col1_3 = rotmat->m6; // -- break; // -- // -- case 2: // -- col1_1 = rotmat->m7; // -- col1_2 = rotmat->m8; // -- col1_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (col2) { // -- case 0: // -- col2_1 = rotmat->m1; // -- col2_2 = rotmat->m2; // -- col2_3 = rotmat->m3; // -- break; // -- // -- case 1: // -- col2_1 = rotmat->m4; // -- col2_2 = rotmat->m5; // -- col2_3 = rotmat->m6; // -- break; // -- // -- case 2: // -- col2_1 = rotmat->m7; // -- col2_2 = rotmat->m8; // -- col2_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (col2) { // -- case 0: // -- rotmat->m1 = -col1_1; // -- rotmat->m2 = -col1_2; // -- rotmat->m3 = -col1_3; // -- break; // -- // -- case 1: // -- rotmat->m4 = -col1_1; // -- rotmat->m5 = -col1_2; // -- rotmat->m6 = -col1_3; // -- break; // -- // -- case 2: // -- rotmat->m7 = -col1_1; // -- rotmat->m8 = -col1_2; // -- rotmat->m9 = -col1_3; // -- break; // -- } // -- // -- switch (col1) { // -- case 0: // -- rotmat->m1 = -col2_1; // -- rotmat->m2 = -col2_2; // -- rotmat->m3 = -col2_3; // -- break; // -- // -- case 1: // -- rotmat->m4 = -col2_1; // -- rotmat->m5 = -col2_2; // -- rotmat->m6 = -col2_3; // -- break; // -- // -- case 2: // -- rotmat->m7 = -col2_1; // -- rotmat->m8 = -col2_2; // -- rotmat->m9 = -col2_3; // -- break; // -- } // -- // -- } // -- // -- void swap_negate_rows(vms_matrix *rotmat, int row1, int row2) // -- { // -- fix row1_1,row1_2,row1_3; // -- fix row2_1,row2_2,row2_3; // -- // -- switch (row1) { // -- case 0: // -- row1_1 = rotmat->m1; // -- row1_2 = rotmat->m4; // -- row1_3 = rotmat->m7; // -- break; // -- // -- case 1: // -- row1_1 = rotmat->m2; // -- row1_2 = rotmat->m5; // -- row1_3 = rotmat->m8; // -- break; // -- // -- case 2: // -- row1_1 = rotmat->m3; // -- row1_2 = rotmat->m6; // -- row1_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (row2) { // -- case 0: // -- row2_1 = rotmat->m1; // -- row2_2 = rotmat->m4; // -- row2_3 = rotmat->m7; // -- break; // -- // -- case 1: // -- row2_1 = rotmat->m2; // -- row2_2 = rotmat->m5; // -- row2_3 = rotmat->m8; // -- break; // -- // -- case 2: // -- row2_1 = rotmat->m3; // -- row2_2 = rotmat->m6; // -- row2_3 = rotmat->m9; // -- break; // -- } // -- // -- switch (row2) { // -- case 0: // -- rotmat->m1 = -row1_1; // -- rotmat->m4 = -row1_2; // -- rotmat->m7 = -row1_3; // -- break; // -- // -- case 1: // -- rotmat->m2 = -row1_1; // -- rotmat->m5 = -row1_2; // -- rotmat->m8 = -row1_3; // -- break; // -- // -- case 2: // -- rotmat->m3 = -row1_1; // -- rotmat->m6 = -row1_2; // -- rotmat->m9 = -row1_3; // -- break; // -- } // -- // -- switch (row1) { // -- case 0: // -- rotmat->m1 = -row2_1; // -- rotmat->m4 = -row2_2; // -- rotmat->m7 = -row2_3; // -- break; // -- // -- case 1: // -- rotmat->m2 = -row2_1; // -- rotmat->m5 = -row2_2; // -- rotmat->m8 = -row2_3; // -- break; // -- // -- case 2: // -- rotmat->m3 = -row2_1; // -- rotmat->m6 = -row2_2; // -- rotmat->m9 = -row2_3; // -- break; // -- } // -- // -- } // -- // -- // ------------------------------------------------------------------------------------------------ // -- void side_based_matrix(vms_matrix *rotmat,int destside) // -- { // -- vms_angvec rotvec; // -- vms_matrix r1,rtemp; // -- // -- switch (destside) { // -- case WLEFT: // -- // swap_negate_columns(rotmat,1,2); // -- // swap_negate_rows(rotmat,1,2); // -- break; // -- // -- case WTOP: // -- break; // -- // -- case WRIGHT: // -- // swap_negate_columns(rotmat,1,2); // -- // swap_negate_rows(rotmat,1,2); // -- break; // -- // -- case WBOTTOM: // -- break; // -- // -- case WFRONT: // -- break; // -- // -- case WBACK: // -- break; // -- } // -- // -- } // ------------------------------------------------------------------------------------------------ // Rotate a group about a point. // The segments in the group are indicated (by segment number) in group_seglist. There are group_size segments. // The point about which the groups is rotated is the center of first_seg:first_side. // delta_flag: // 0 absolute rotation, destination specified in terms of base_seg:base_side, used in moving or copying a group // 1 relative rotation, destination specified relative to current orientation of first_seg:first_side // Note: The group must exist in the mine, consisting of actual points in the world. If any points in the // segments in the group are shared by segments not in the group, those points will get rotated and the // segments not in the group will have their shapes modified. // Return value: // 0 group rotated // 1 unable to rotate group void med_create_group_rotation_matrix(vms_matrix *result_mat, int delta_flag, segment *first_seg, int first_side, segment *base_seg, int base_side, vms_matrix *orient_matrix, int orientation) { vms_matrix rotmat2,rotmat,rotmat3,rotmat4; vms_angvec pbh = {0,0,0}; // Determine whether this rotation is a delta rotation, meaning to just rotate in place, or an absolute rotation, // which means that the destination rotation is specified, not as a delta, but as an absolute if (delta_flag) { // Create rotation matrix describing rotation. med_extract_matrix_from_segment(first_seg, &rotmat4); // get rotation matrix describing current orientation of first seg set_matrix_based_on_side(&rotmat4, first_side); rotmat3 = *orient_matrix; vm_transpose_matrix(&rotmat3); vm_matrix_x_matrix(&rotmat,&rotmat4,&rotmat3); // this is the desired orientation of the new segment vm_transpose_matrix(&rotmat4); vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat4); // this is the desired orientation of the new segment } else { // Create rotation matrix describing rotation. med_extract_matrix_from_segment(base_seg, &rotmat); // get rotation matrix describing desired orientation set_matrix_based_on_side(&rotmat, base_side); // modify rotation matrix for desired side // If the new segment is to be attached without rotation, then its orientation is the same as the base_segment vm_matrix_x_matrix(&rotmat4,&rotmat,orient_matrix); // this is the desired orientation of the new segment pbh.b = orientation*16384; vm_angles_2_matrix(&rotmat3,&pbh); vm_matrix_x_matrix(&rotmat, &rotmat4, &rotmat3); rotmat4 = rotmat; rotmat = rotmat4; med_extract_matrix_from_segment(first_seg, &rotmat3); // get rotation matrix describing current orientation of first seg // It is curious that the following statement has no analogue in the med_attach_segment_rotated code. // Perhaps it is because segments are always attached at their front side. If the back side is the side // passed to the function, then the matrix is not modified, which might suggest that what you need to do below // is use Side_opposite[first_side]. set_matrix_based_on_side(&rotmat3, Side_opposite[first_side]); // modify rotation matrix for desired side vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix vm_matrix_x_matrix(&rotmat2,&rotmat,&rotmat3); // now rotmat2 takes the current segment to the desired orientation vm_transpose_matrix(&rotmat2); } *result_mat = rotmat2; } // ----------------------------------------------------------------------------------------- // Rotate all vertices and objects in group. void med_rotate_group(vms_matrix *rotmat, short *group_seglist, int group_size, segment *first_seg, int first_side) { int v,s, objnum; sbyte vertex_list[MAX_VERTICES]; vms_vector rotate_center; compute_center_point_on_side(&rotate_center, first_seg, first_side); // Create list of points to rotate. for (v=0; v<=Highest_vertex_index; v++) vertex_list[v] = 0; for (s=0; sverts[v]] = 1; // Rotate center of all objects in group. objnum = sp->objects; while (objnum != -1) { vms_vector tv, tv1; vm_vec_sub(&tv1,&Objects[objnum].pos,&rotate_center); vm_vec_rotate(&tv,&tv1,rotmat); vm_vec_add(&Objects[objnum].pos, &tv, &rotate_center); objnum = Objects[objnum].next; } } // Do the pre-rotation xlate, do the rotation, do the post-rotation xlate for (v=0; v<=Highest_vertex_index; v++) if (vertex_list[v]) { vms_vector tv,tv1; vm_vec_sub(&tv1,&Vertices[v],&rotate_center); vm_vec_rotate(&tv,&tv1,rotmat); vm_vec_add(&Vertices[v],&tv,&rotate_center); } } // ------------------------------------------------------------------------------------------------ void cgl_aux(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs) { int i, side; int curseg = segp-Segments; for (i=0; i= MAX_SEGMENTS)) { Int3(); } if (!Been_visited[segp-Segments]) { seglistp[(*num_segs)++] = segp-Segments; Been_visited[segp-Segments] = 1; for (side=0; sidechildren[side])) cgl_aux(&Segments[segp->children[side]], seglistp, num_segs, ignore_list, num_ignore_segs); } } // ------------------------------------------------------------------------------------------------ // Sets Been_visited[n] if n is reachable from segp void create_group_list(segment *segp, short *seglistp, int *num_segs, short *ignore_list, int num_ignore_segs) { int i; for (i=0; ichildren[sidenum]; if (IS_CHILD(seg)) { for (ss=0; ssverts[v]]) { sp->verts[v] = new_vertex_ids[sp->verts[v]]; } } } // end for (s=0... // Now, copy new_segment_ids into segment_ids for (s=0; schildren[base_side])) { editor_status("Error -- unable to copy group, base_seg:base_side must be free."); return 1; } if (num_groups == MAX_GROUPS) { x = ui_messagebox( -2, -2, 2, "Warning: You have reached the MAXIMUM group number limit. Continue?", "No", "Yes" ); if (x==1) return 0; } if (num_groups < MAX_GROUPS) { num_groups++; new_current_group = num_groups-1; } else new_current_group = 0; Assert(current_group >= 0); // Find groupsegp index for (s=0;sverts[v]] = 1; else { for (v=0; v<=Highest_vertex_index; v++) in_vertex_list[v] = 0; for (s=0; schildren[c])) { if (!in_group(segp->children[c], new_current_group)) { segp->children[c] = -1; validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment } } } copy_uvs_seg_to_seg(&New_segment, Groupsegp[new_current_group]); // Now do the copy // First, xlate all vertices so center of group_seg:group_side is at origin compute_center_point_on_side(&srcv,group_seg,group_side); for (v=0; v<=Highest_vertex_index; v++) if (in_vertex_list[v]) vm_vec_sub2(&Vertices[v],&srcv); // Now, translate all object positions. for (s=0; schildren[base_side])) if (base_seg->children[base_side] != group_seg-Segments) { editor_status("Error -- unable to move group, base_seg:base_side must be free or point to group_seg."); return 1; } // // See if any vertices in base_seg are contained in any vertex in group_list // for (v=0; vverts[v]) { // editor_status("Error -- unable to move group, it shares a vertex with destination segment."); // return 1; // } for (v=0; v<=Highest_vertex_index; v++) { in_vertex_list[v] = 0; out_vertex_list[v] = 0; } // Make a list of all vertices in group. for (s=0; sverts[vv] == v) sp->verts[vv] = new_vertex_id; } } for (s=0;schildren[c])) { csegp = &Segments[segp->children[c]]; if (csegp->group != current_group) { for (d=0; dchildren[d])) { dsegp = &Segments[csegp->children[d]]; if (dsegp->group == current_group) { csegp->children[d] = -1; validate_segment_side(csegp,d); // we have converted a connection to a side so validate the segment } } segp->children[c] = -1; validate_segment_side(segp,c); // we have converted a connection to a side so validate the segment } } } copy_uvs_seg_to_seg(&New_segment, Groupsegp[current_group]); // Now do the move // First, xlate all vertices so center of group_seg:group_side is at origin compute_center_point_on_side(&srcv,group_seg,group_side); for (v=0; v<=Highest_vertex_index; v++) if (in_vertex_list[v]) vm_vec_sub2(&Vertices[v],&srcv); // Now, move all object positions. for (s=0; schildren[(int) Side_opposite[Curside]])) { // -- I don't understand this, MK, 01/25/94: if (Cursegp->children[Curside] != group_seg-Segments) { editor_status("Error -- unable to rotate group, Cursegp:Side_opposite[Curside] cannot be free."); return 1; } current_group_save = current_group; current_group = ROT_GROUP; Groupsegp[ROT_GROUP] = Cursegp; save_selected_segs(&n_selected_segs_save, selected_segs_save); GroupList[ROT_GROUP].num_segments = 0; newseg = Cursegp - Segments; newseg_side = Side_opposite[Curside]; // Create list of segments to rotate. // Sever connection between first seg to rotate and its connection on Side_opposite[Curside]. child_save = Cursegp->children[newseg_side]; // save connection we are about to sever Cursegp->children[newseg_side] = -1; // sever connection create_group_list(Cursegp, GroupList[ROT_GROUP].segments, &GroupList[ROT_GROUP].num_segments, Selected_segs, 0); // create list of segments in group Cursegp->children[newseg_side] = child_save; // restore severed connection GroupList[ROT_GROUP].segments[0] = newseg; baseseg = Segments[newseg].children[newseg_side]; if (!IS_CHILD(baseseg)) { editor_status("Error -- unable to rotate segment, side opposite curside is not attached."); restore_selected_segs(n_selected_segs_save,selected_segs_save); current_group = current_group_save; return 1; } baseseg_side = find_connect_side(&Segments[newseg], &Segments[baseseg]); med_extract_matrix_from_segment(&Segments[newseg],&tm1); tm1 = vmd_identity_matrix; vm_angles_2_matrix(&tm2,pbh); vm_matrix_x_matrix(&orient_matrix,&tm1,&tm2); Segments[baseseg].children[baseseg_side] = -1; Segments[newseg].children[newseg_side] = -1; if (!med_move_group(1, &Segments[baseseg], baseseg_side, &Segments[newseg], newseg_side, &orient_matrix, 0)) { Cursegp = &Segments[newseg]; med_create_new_segment_from_cursegp(); // validate_selected_segments(); med_propagate_tmaps_to_segments(&Segments[baseseg], &Segments[newseg], 1); med_propagate_tmaps_to_back_side(&Segments[newseg], Curside, 1); } restore_selected_segs(n_selected_segs_save,selected_segs_save); current_group = current_group_save; return 1; } // ----------------------------------------------------------------------------- // Attach segment in the new-fangled way, which is by using the CopyGroup code. int RotateSegmentNew(vms_angvec *pbh) { int rval; autosave_mine(mine_filename); rval = rotate_segment_new(pbh); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; warn_if_concave_segment(Cursegp); return rval; } static char current_tmap_list[MAX_TEXTURES][13]; // ----------------------------------------------------------------------------- // Save mine will: // 1. Write file info, header info, editor info, vertex data, segment data, // and new_segment in that order, marking their file offset. // 2. Go through all the fields and fill in the offset, size, and sizeof // values in the headers. int med_save_group( char *filename, int *vertex_ids, short *segment_ids, int num_vertices, int num_segments) { PHYSFS_file * SaveFile; int header_offset, editor_offset, vertex_offset, segment_offset, texture_offset; char ErrorMessage[100]; int i, j, k; int segnum; segment tseg; vms_vector tvert; int found; SaveFile = PHYSFSX_openWriteBuffered( filename ); if (!SaveFile) { sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename ); ui_messagebox( -2, -2, 1, ErrorMessage, "Ok" ); return 1; } //===================== SAVE FILE INFO ======================== group_fileinfo.fileinfo_version = MINE_VERSION; group_fileinfo.fileinfo_sizeof = sizeof(group_fileinfo); group_fileinfo.header_offset = -1; group_fileinfo.header_size = sizeof(group_header); group_fileinfo.editor_offset = -1; group_fileinfo.editor_size = sizeof(group_editor); group_fileinfo.vertex_offset = -1; group_fileinfo.vertex_howmany = num_vertices; group_fileinfo.vertex_sizeof = sizeof(vms_vector); group_fileinfo.segment_offset = -1; group_fileinfo.segment_howmany = num_segments; group_fileinfo.segment_sizeof = sizeof(segment); group_fileinfo.texture_offset = -1; group_fileinfo.texture_howmany = 0; group_fileinfo.texture_sizeof = 13; // num characters in a name // Write the fileinfo PHYSFS_write( SaveFile, &group_fileinfo, sizeof(group_fileinfo), 1); //===================== SAVE HEADER INFO ======================== group_header.num_vertices = num_vertices; group_header.num_segments = num_segments; // Write the editor info header_offset = PHYSFS_tell(SaveFile); PHYSFS_write( SaveFile, &group_header, sizeof(group_header), 1); //===================== SAVE EDITOR INFO ========================== group_editor.newsegment_offset = -1; // To be written group_editor.newsegment_size = sizeof(segment); // Next 3 vars added 10/07 by JAS if (Groupsegp[current_group]) { segnum = Groupsegp[current_group]-Segments; for (i=0;i -1 ) { if (PHYSFSX_fseek( LoadFile,group_fileinfo.header_offset, SEEK_SET )) Error( "Error seeking to header_offset in group.c" ); if (PHYSFS_read( LoadFile, &group_header, group_fileinfo.header_size,1 )!=1) Error( "Error reading group_header in group.c" ); } //===================== READ EDITOR INFO ========================== // Set default values group_editor.current_seg = 0; group_editor.newsegment_offset = -1; // To be written group_editor.newsegment_size = sizeof(segment); group_editor.Groupsegp = -1; group_editor.Groupside = 0; if (group_fileinfo.editor_offset > -1 ) { if (PHYSFSX_fseek( LoadFile,group_fileinfo.editor_offset, SEEK_SET )) Error( "Error seeking to editor_offset in group.c" ); if (PHYSFS_read( LoadFile, &group_editor, group_fileinfo.editor_size,1 )!=1) Error( "Error reading group_editor in group.c" ); } //===================== READ VERTEX INFO ========================== if ( (group_fileinfo.vertex_offset > -1) && (group_fileinfo.vertex_howmany > 0)) { if (PHYSFSX_fseek( LoadFile,group_fileinfo.vertex_offset, SEEK_SET )) Error( "Error seeking to vertex_offset in group.c" ); for (i=0;i -1) && (group_fileinfo.segment_howmany > 0)) { if (PHYSFSX_fseek( LoadFile,group_fileinfo.segment_offset, SEEK_SET )) Error( "Error seeking to segment_offset in group.c" ); for (i=0;i -1) && (group_fileinfo.texture_howmany > 0)) { if (PHYSFSX_fseek( LoadFile, group_fileinfo.texture_offset, SEEK_SET )) Error( "Error seeking to texture_offset in gamemine.c" ); for (i=0; i< group_fileinfo.texture_howmany; i++ ) { if (PHYSFS_read( LoadFile, &old_tmap_list[i], group_fileinfo.texture_sizeof, 1 )!=1) Error( "Error reading old_tmap_list[i] in gamemine.c" ); } } //=============== GENERATE TEXTURE TRANSLATION TABLE =============== translate = 0; Assert (NumTextures < MAX_TEXTURES); { hashtable ht; hashtable_init( &ht, NumTextures ); // Remove all the file extensions in the textures list for (i=0;igroup == current_group) { Cursegp->group = -1; delete_segment_from_group( Cursegp-Segments, current_group ); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message_fmt("Segment Ungrouped from Group %d.", current_group); return 1; } else return 0; } int GroupSegment( void ) { if (Cursegp->group == -1) { Cursegp->group = current_group; add_segment_to_group( Cursegp-Segments, current_group ); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message_fmt("Segment Added to Group %d.", current_group); return 1; } else return 0; } int Degroup( void ) { int i; // GroupList[current_group].num_segments = 0; // Groupsegp[current_group] = 0; if (num_groups==0) return 0; for (i=0; i num_groups-1) current_group--; if (num_groups == 0) current_group = -1; if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group UNgrouped."); return 1; } void NextGroup( void ) { if (num_groups > 0) { current_group++; if (current_group >= num_groups ) current_group = 0; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; } else editor_status("No Next Group\n"); } void PrevGroup( void ) { if (num_groups > 0) { current_group--; if (current_group < 0 ) current_group = num_groups-1; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; } else editor_status("No Previous Group\n"); } // Returns: // 0 = successfully selected // 1 = bad group number int select_group( int num ) { if ((num>=0) && (numchildren[Groupside[current_group]]; if (attach_seg != -1) { int i; for (i=0; ichildren[Groupside[current_group]]); return 1; } } med_compress_mine(); if (!med_copy_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix)) { autosave_mine(mine_filename); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group copied."); return 0; } else return 1; } // ----------------------------------------------------------------------------- int RotateGroup(void) { if (!Groupsegp[current_group]) { editor_status("Error -- Cannot rotate group, no group segment."); return 1; } Group_orientation[current_group]++; if ((Group_orientation[current_group] <0) || (Group_orientation[current_group] >4)) Group_orientation[current_group]=0; med_compress_mine(); if (!med_move_group(0, Cursegp, Curside, Groupsegp[current_group], Groupside[current_group], &vmd_identity_matrix, Group_orientation[current_group])) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group rotated."); return 0; } else return 1; } // ----------------------------------------------------------------------------- // Creates a group from all segments connected to marked segment. int SubtractFromGroup(void) { int x, s, original_group; short *gp; int cur_num_segs; if (!Markedsegp) { editor_status("Error -- Cannot create group, no marked segment."); return 1; } med_compress_mine(); autosave_mine(mine_filename); if (num_groups == MAX_GROUPS) { x = ui_messagebox( -2, -2, 2, "Warning: You are about to wipe out a group.", "ARGH! NO!", "No problemo." ); if (x==1) return 0; } if (current_group == -1) { editor_status("Error -- No current group. Cannot subtract."); return 1; } original_group = current_group; current_group = (current_group + 1) % MAX_GROUPS; // Create a list of segments to copy. GroupList[current_group].num_segments = 0; create_group_list(Markedsegp, GroupList[current_group].segments, &GroupList[current_group].num_segments, Selected_segs, N_selected_segs); // Now, scan the two groups, forming a group which consists of only those segments common to the two groups. gp = GroupList[current_group].segments; cur_num_segs = GroupList[current_group].num_segments; for (s=0; s num_groups-1) current_group--; if (num_groups==0) current_group = -1; strcpy(undo_status[Autosave_count], "Delete Group UNDONE."); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Group deleted."); // warn_if_concave_segments(); // This could be faster -- just check if deleted segment was concave, warn accordingly return 1; } int MarkGroupSegment( void ) { if ((Cursegp->group != -1) && (Cursegp->group == current_group)) { autosave_mine(mine_filename); Groupsegp[current_group] = Cursegp; Groupside[current_group] = Curside; editor_status("Group Segment Marked."); Update_flags |= UF_ED_STATE_CHANGED; strcpy(undo_status[Autosave_count], "Mark Group Segment UNDONE."); mine_changed = 1; return 1; } else return 0; } dxx-rebirth-0.58.1-d1x/editor/info.c000066400000000000000000000255041217717257200171450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Print debugging info in ui. * */ #include #include #include #ifdef DO_MEMINFO #include #endif #include "inferno.h" #include "window.h" #include "segment.h" #include "gr.h" #include "ui.h" #include "editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "textures.h" #include "object.h" #include "ai.h" #include "texpage.h" // Textue selection paging stuff #include "objpage.h" // Object selection paging stuff #include "wall.h" #include "switch.h" int init_info; #ifdef DO_MEMINFO struct meminfo { int LargestBlockAvail; int MaxUnlockedPage; int LargestLockablePage; int LinAddrSpace; int NumFreePagesAvail; int NumPhysicalPagesFree; int TotalPhysicalPages; int FreeLinAddrSpace; int SizeOfPageFile; int Reserved[3]; } MemInfo; #define DPMI_INT 0x31 void read_mem_info() { union REGS regs; struct SREGS sregs; regs.x.eax = 0x00000500; memset( &sregs, 0, sizeof(sregs) ); sregs.es = FP_SEG( &MemInfo ); regs.x.edi = FP_OFF( &MemInfo ); int386x( DPMI_INT, ®s, ®s, &sregs ); } #endif char * get_object_type(int num, char *name) { switch (num) { case OBJ_NONE: strcpy(name, "OBJ_NONE "); break; case OBJ_WALL: strcpy(name, "OBJ_WALL "); break; case OBJ_FIREBALL: strcpy(name, "OBJ_FIREBALL"); break; case OBJ_ROBOT: strcpy(name, "OBJ_ROBOT "); break; case OBJ_HOSTAGE: strcpy(name, "OBJ_HOSTAGE "); break; case OBJ_PLAYER: strcpy(name, "OBJ_PLAYER "); break; case OBJ_WEAPON: strcpy(name, "OBJ_WEAPON "); break; case OBJ_CAMERA: strcpy(name, "OBJ_CAMERA "); break; case OBJ_POWERUP: strcpy(name, "OBJ_POWERUP "); break; default: strcpy(name, " (unknown) "); break; } return name; } char * get_control_type(int num, char *name) { switch (num) { case CT_NONE: strcpy(name, "CT_NONE "); break; case CT_AI: strcpy(name, "CT_AI "); break; case CT_EXPLOSION: strcpy(name, "CT_EXPLOSION "); break; //case CT_MULTIPLAYER: strcpy(name, "CT_MULTIPLAYER"); break; case CT_FLYING: strcpy(name, "CT_FLYING "); break; case CT_SLEW: strcpy(name, "CT_SLEW "); break; case CT_FLYTHROUGH: strcpy(name, "CT_FLYTHROUGH "); break; //case CT_DEMO: strcpy(name, "CT_DEMO "); break; //case CT_ROBOT_FLYTHROUGH: strcpy(name, "CT_FLYTHROUGH "); break; case CT_WEAPON: strcpy(name, "CT_WEAPON "); break; default: strcpy(name, " (unknown) "); break; } return name; } char * get_movement_type(int num, char *name) { switch (num) { case MT_NONE: strcpy(name, "MT_NONE "); break; case MT_PHYSICS: strcpy(name, "MT_PHYSICS "); break; //case MT_MULTIPLAYER: strcpy(name, "MT_MULTIPLAYER"); break; default: strcpy(name, " (unknown) "); break; } return name; } char * get_ai_behavior(int num, char *name) { #define AIB_STILL 0x80 #define AIB_NORMAL 0x81 #define AIB_HIDE 0x82 #define AIB_RUN_FROM 0x83 #define AIB_FOLLOW_PATH 0x84 switch (num) { case AIB_STILL: strcpy(name, "STILL "); break; case AIB_NORMAL: strcpy(name, "NORMAL "); break; case AIB_HIDE: strcpy(name, "HIDE "); break; case AIB_RUN_FROM: strcpy(name, "RUN_FROM "); break; case AIB_FOLLOW_PATH: strcpy(name, "FOLLOW_PATH "); break; default: strcpy(name, " (unknown) "); break; } return name; } // --------------------------------------------------------------------------------------------------- void info_display_object_placement(int show_all) { static int old_Cur_object_index; static int old_type; static int old_movement_type; static int old_control_type; static int old_mode; char name[30]; if (init_info | show_all) { old_Cur_object_index = -2; old_type = -2; old_movement_type = -2; old_control_type = -2; old_mode = -2; } if ( ( Cur_object_index != old_Cur_object_index) || ( Objects[Cur_object_index].type != old_type) || ( Objects[Cur_object_index].movement_type != old_movement_type) || ( Objects[Cur_object_index].control_type != old_control_type) || ( Objects[Cur_object_index].ctype.ai_info.behavior != old_mode) ) { gr_uprintf( 0, 0, "Object id: %4d\n", Cur_object_index); gr_uprintf( 0, 16, "Type: %s\n", get_object_type(Objects[Cur_object_index].type , name)); gr_uprintf( 0, 32, "Movmnt: %s\n", get_movement_type(Objects[Cur_object_index].movement_type, name)); gr_uprintf( 0, 48, "Cntrl: %s\n", get_control_type(Objects[Cur_object_index].control_type, name)); gr_uprintf( 0, 64, "Mode: %s\n", get_ai_behavior(Objects[Cur_object_index].ctype.ai_info.behavior, name)); old_Cur_object_index = Cur_object_index; old_type = Objects[Cur_object_index].type; old_movement_type = Objects[Cur_object_index].movement_type; old_mode = Objects[Cur_object_index].control_type; old_mode = Objects[Cur_object_index].ctype.ai_info.behavior; } } // --------------------------------------------------------------------------------------------------- void info_display_segsize(int show_all) { static int old_SegSizeMode; char name[30]; if (init_info | show_all) { old_SegSizeMode = -2; } if (old_SegSizeMode != SegSizeMode ) { switch (SegSizeMode) { case SEGSIZEMODE_FREE: strcpy(name, "free "); break; case SEGSIZEMODE_ALL: strcpy(name, "all "); break; case SEGSIZEMODE_CURSIDE: strcpy(name, "curside"); break; case SEGSIZEMODE_EDGE: strcpy(name, "edge "); break; case SEGSIZEMODE_VERTEX: strcpy(name, "vertex "); break; default: Error("Illegal value for SegSizeMode in info.c/info_display_segsize\n"); } gr_uprintf( 0, 0, "Mode: %s\n", name); old_SegSizeMode = SegSizeMode; } } extern int num_objects; // --------------------------------------------------------------------------------------------------- void info_display_default(int show_all) { static int old_Num_segments = -1; static int old_Num_vertices = -1; static int old_Num_objects = -1; static int old_Cursegp_num = -1; static int old_Curside = -1; static int old_Cursegp_num_for_verts = -1; static int old_CurrentTexture = -1; static int old_Num_walls = -1; static int old_Num_triggers = -1; if (init_info | show_all) { init_info = 0; old_Num_segments = -1; old_Num_vertices = -1; old_Num_objects = -1; old_Cursegp_num = -1; old_Cursegp_num_for_verts = -1; old_Curside = -1; old_CurrentTexture = -1; old_Num_walls = -1; old_Num_triggers = -1; } gr_set_fontcolor(CBLACK,CWHITE); //--------------- Number of segments ---------------- if ( old_Num_segments != Num_segments ) { gr_uprintf( 0, 0, "Segments: %4d/%4d", Num_segments, MAX_SEGMENTS ); old_Num_segments = Num_segments; } //---------------- Number of vertics ----------------- if ( old_Num_vertices != Num_vertices ) { gr_uprintf( 0, 16, "Vertices: %4d/%4d", Num_vertices, MAX_VERTICES ); old_Num_vertices = Num_vertices; } //---------------- Number of objects ----------------- if ( old_Num_objects != num_objects ) { gr_uprintf( 0, 32, "Objs: %3d/%3d", num_objects, MAX_OBJECTS ); old_Num_objects = num_objects; } //--------------- Current_segment_number ------------- //--------------- Current_side_number ------------- if (( old_Cursegp_num != Cursegp-Segments ) || ( old_Curside != Curside )) { gr_uprintf( 0, 48, "Cursegp/side: %3ld/%1d", Cursegp-Segments, Curside); gr_uprintf( 0, 128, " tmap1,2,o: %3d/%3dx%1d", Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2 & 0x3FFF, (Cursegp->sides[Curside].tmap_num2 >> 14) & 3); old_Cursegp_num = Cursegp-Segments; old_Curside = Curside; } //--------------- Current_vertex_numbers ------------- if ( old_Cursegp_num_for_verts != Cursegp-Segments ) { gr_uprintf( 0, 64, "{%3d,%3d,%3d,%3d,", Cursegp->verts[0],Cursegp->verts[1], Cursegp->verts[2],Cursegp->verts[3] ); gr_uprintf( 0, 80," %3d,%3d,%3d,%3d}", Cursegp->verts[4],Cursegp->verts[5], Cursegp->verts[6],Cursegp->verts[7] ); old_Cursegp_num_for_verts = Cursegp-Segments; } //--------------- Num walls/links/triggers ------------------------- if ( old_Num_walls != Num_walls ) { // gr_uprintf( 0, 96, "Walls/Links %d/%d", Num_walls, Num_links ); gr_uprintf( 0, 96, "Walls %3d", Num_walls ); old_Num_walls = Num_walls; } //--------------- Num triggers ---------------------- if ( old_Num_triggers != Num_triggers ) { gr_uprintf( 0, 112, "Num_triggers %2d", Num_triggers ); old_Num_triggers = Num_triggers; } //--------------- Current texture number ------------- if ( old_CurrentTexture != CurrentTexture ) { gr_uprintf( 0, 144, "Tex/Light: %3d %5.2f", CurrentTexture, f2fl(TmapInfo[CurrentTexture].lighting)); old_CurrentTexture = CurrentTexture; } } // ------------------------------------------------------------------------------------ void clear_pad_display(void) { gr_clear_canvas(CWHITE); gr_set_fontcolor( CBLACK, CWHITE ); } // ------------------------------------------------------------------------------------ int info_display_all(window *wind, d_event *event, void *userdata) { static int old_padnum = -1; int padnum,show_all = 1; // always redraw grs_canvas *save_canvas = grd_curcanv; switch (event->type) { case EVENT_WINDOW_DRAW: userdata++; //kill warning gr_set_current_canvas(window_get_canvas(wind)); padnum = ui_pad_get_current(); Assert(padnum <= MAX_PAD_ID); if (padnum != old_padnum) { clear_pad_display(); old_padnum = padnum; //show_all = 1; } switch (padnum) { case OBJECT_PAD_ID: // Object placement info_display_object_placement(show_all); break; case SEGSIZE_PAD_ID: // Segment sizing info_display_segsize(show_all); break; default: info_display_default(show_all); break; } grd_curcanv = save_canvas; return 1; case EVENT_WINDOW_CLOSE: Pad_info = NULL; break; default: break; } return 0; } // ------------------------------------------------------------------------------------ window *info_window_create(void) { window *wind; wind = window_create(Canv_editor, PAD_X + 250, PAD_Y + 8, 180, 160, info_display_all, NULL); if (wind) window_set_modal(wind, 0); return wind; } dxx-rebirth-0.58.1-d1x/editor/kbuild.c000066400000000000000000000144631217717257200174660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for building parts of mines. * */ #include #include "inferno.h" #include "editor/editor.h" #include "editor/esegment.h" #include "gameseg.h" #include "gamesave.h" // ---------- Create a bridge segment between current segment/side and marked segment/side ---------- int CreateBridge() { if (!med_form_bridge_segment(Cursegp,Curside,Markedsegp,Markedside)) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Bridge segment formed."); strcpy(undo_status[Autosave_count], "Bridge segment UNDONE."); warn_if_concave_segments(); } return 1; } // ---------- Form a joint between current segment:side and marked segment:side, modifying marked segment ---------- int FormJoint() { if (!Markedsegp) diagnostic_message("Marked segment not set -- unable to form joint."); else { if (!med_form_joint(Cursegp,Curside,Markedsegp,Markedside)) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Joint formed."); strcpy(undo_status[Autosave_count], "Joint undone."); warn_if_concave_segments(); } } return 1; } // ---------- Create a bridge segment between current segment:side adjacent segment:side ---------- int CreateAdjacentJoint() { int adj_side; segment *adj_sp; if (med_find_adjacent_segment_side(Cursegp, Curside, &adj_sp, &adj_side)) { if (Cursegp->children[Curside] != adj_sp-Segments) { med_form_joint(Cursegp,Curside,adj_sp,adj_side); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Joint segment formed."); strcpy(undo_status[Autosave_count], "Joint segment undone."); warn_if_concave_segments(); } else editor_status("Attempted to form joint through connected side -- joint segment not formed (you bozo)."); } else editor_status("Could not find adjacent segment -- joint segment not formed."); return 1; } // ---------- Create a bridge segment between current segment:side adjacent segment:side ---------- int CreateSloppyAdjacentJoint() { int adj_side; segment *adj_sp; save_level("SLOPPY.LVL"); if (med_find_closest_threshold_segment_side(Cursegp, Curside, &adj_sp, &adj_side, 20*F1_0)) { if (Cursegp->children[Curside] != adj_sp-Segments) { if (!med_form_joint(Cursegp,Curside,adj_sp,adj_side)) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Sloppy Joint segment formed."); strcpy(undo_status[Autosave_count], "Sloppy Joint segment undone."); warn_if_concave_segments(); } else editor_status("Couldn't form sloppy joint.\n"); } else editor_status("Attempted to form sloppy joint through connected side -- joint segment not formed (you bozo)."); } else editor_status("Could not find close threshold segment -- joint segment not formed."); return 1; } // -------------- Create all sloppy joints within CurrentGroup ------------------ int CreateSloppyAdjacentJointsGroup() { int adj_side; segment *adj_sp; int num_segs = GroupList[current_group].num_segments; short *segs = GroupList[current_group].segments; segment *segp; int done_been_a_change = 0; int segind, sidenum; for (segind=0; segindchildren[sidenum])) if (med_find_closest_threshold_segment_side(segp, sidenum, &adj_sp, &adj_side, 5*F1_0)) { if (adj_sp->group == segp->group) { if (segp->children[sidenum] != adj_sp-Segments) if (!med_form_joint(segp, sidenum, adj_sp,adj_side)) done_been_a_change = 1; } } } if (done_been_a_change) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Sloppy Joint segment formed."); strcpy(undo_status[Autosave_count], "Sloppy Joint segment undone."); warn_if_concave_segments(); } return 1; } // ---------- Create a bridge segment between current segment and all adjacent segment:side ---------- int CreateAdjacentJointsSegment() { int adj_side,s; segment *adj_sp; med_combine_duplicate_vertices(Vertex_active); for (s=0; schildren[s] != adj_sp-Segments) { med_form_joint(Cursegp,s,adj_sp,adj_side); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Adjacent Joint segment formed."); strcpy(undo_status[Autosave_count], "Adjacent Joint segment UNDONE."); warn_if_concave_segments(); } } return 1; } // ---------- Create a bridge segment between all segment:side and all adjacent segment:side ---------- int CreateAdjacentJointsAll() { int adj_side,seg,s; segment *adj_sp; med_combine_duplicate_vertices(Vertex_active); for (seg=0; seg<=Highest_segment_index; seg++) for (s=0; s #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "kdefs.h" static fix r1scale, r4scale; static int curve; int InitCurve() { curve = 0; return 1; } int GenerateCurve() { if ( (Markedsegp != 0) && !IS_CHILD(Markedsegp->children[Markedside])) { r1scale = r4scale = F1_0*20; autosave_mine( mine_filename ); diagnostic_message("Curve Generated."); Update_flags |= UF_WORLD_CHANGED; curve = generate_curve(r1scale, r4scale); mine_changed = 1; if (curve == 1) { strcpy(undo_status[Autosave_count], "Curve Generation UNDONE.\n"); } if (curve == 0) diagnostic_message("Cannot generate curve -- check Current segment."); } else diagnostic_message("Cannot generate curve -- check Marked segment."); warn_if_concave_segments(); return 1; } int DecreaseR4() { if (curve) { Update_flags |= UF_WORLD_CHANGED; delete_curve(); r4scale -= F1_0; generate_curve(r1scale, r4scale); diagnostic_message("R4 vector decreased."); mine_changed = 1; warn_if_concave_segments(); } return 1; } int IncreaseR4() { if (curve) { Update_flags |= UF_WORLD_CHANGED; delete_curve(); r4scale += F1_0; generate_curve(r1scale, r4scale); diagnostic_message("R4 vector increased."); mine_changed = 1; warn_if_concave_segments(); } return 1; } int DecreaseR1() { if (curve) { Update_flags |= UF_WORLD_CHANGED; delete_curve(); r1scale -= F1_0; generate_curve(r1scale, r4scale); diagnostic_message("R1 vector decreased."); mine_changed = 1; warn_if_concave_segments(); } return 1; } int IncreaseR1() { if (curve) { Update_flags |= UF_WORLD_CHANGED; delete_curve(); r1scale += F1_0; generate_curve(r1scale, r4scale); diagnostic_message("R1 vector increased."); mine_changed = 1; warn_if_concave_segments(); } return 1; } int DeleteCurve() { // fix_bogus_uvs_all(); set_average_light_on_curside(); if (curve) { Update_flags |= UF_WORLD_CHANGED; delete_curve(); curve = 0; mine_changed = 1; diagnostic_message("Curve Deleted."); warn_if_concave_segments(); } return 1; } int SetCurve() { if (curve) curve = 0; //autosave_mine( mine_filename ); //strcpy(undo_status[Autosave_count], "Curve Generation UNDONE.\n"); return 1; } dxx-rebirth-0.58.1-d1x/editor/kfuncs.c000066400000000000000000000435111217717257200175010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * . * */ #include #include "inferno.h" #include "func.h" #include "editor/kdefs.h" #include "segment.h" #include "editor/editor.h" #include "dxxerror.h" #include "slew.h" #include "gamesave.h" #include "editor/eobject.h" #include "editor/medwall.h" // Test function prototypes (replace Test1, 2 and 3 with whatever function you wish to test.) extern void test_create_path(); extern void test_create_all_paths(); extern void test_create_path_many(); extern void create_all_paths(); extern void test_create_all_anchors(); // extern void make_curside_bottom_side(); extern void move_object_to_mouse_click(); extern void test_create_n_segment_path(); extern void set_all_modes_to_hover(void); extern void check_for_overlapping_segments(void); extern void init_replacements(); extern void do_replacements(void); extern void do_replacements_all(void); int Test1() { init_replacements(); return 0; } int Test2() { do_replacements(); return 0; } //extern fix fcd_test(void); //extern void test_shortpos(void); int Test3() { Int3(); // Are you sure you want to do this? // This will replace all textures in your replacement list // in all mines. // If you don't want to do this, set eip to the return statement // and continue. do_replacements_all(); return 0; } FUNCTION med_functions[] = { // Test functions { "med-test-1", 0, Test1 }, { "med-test-2", 0, Test2 }, { "med-test-3", 0, Test3 }, // In khelp.c { "med-help", 0, DoHelp }, // In kcurve.c { "med-curve-init", 0, InitCurve }, { "med-curve-generate", 0, GenerateCurve }, { "med-curve-decrease-r4", 0, DecreaseR4 }, { "med-curve-increase-r4", 0, IncreaseR4 }, { "med-curve-decrease-r1", 0, DecreaseR1 }, { "med-curve-increase-r1", 0, IncreaseR1 }, { "med-curve-delete", 0, DeleteCurve }, { "med-curve-set", 0, SetCurve }, // In kmine.c { "med-mine-save", 0, SaveMine }, //{ "med-mine-load", 0, LoadMine }, { "med-mine-menu", 0, MineMenu }, { "med-mine-create-new", 0, CreateNewMine }, //{ "med-mine-load-old", 0, LoadOldMine }, { "med-situation-save", 0, SaveSituation }, { "med-situation-load", 0, LoadSituation }, { "med-restore-game-state", 0, RestoreGameState }, //{ "load-mine-only", 0, LoadMineOnly }, // In kgame.c { "med-game-save", 0, SaveGameData }, { "med-game-load", 0, LoadGameData }, // In kview.c { "med-view-zoom-out", 0, ZoomOut }, { "med-view-zoom-in", 0, ZoomIn }, { "med-view-move-away", 0, MoveAway }, { "med-view-move-closer", 0, MoveCloser }, { "med-view-toggle-chase", 0, ToggleChaseMode }, // In kbuild.c { "med-build-bridge", 0, CreateBridge }, { "med-build-joint", 0, FormJoint }, { "med-build-adj-joint", 0, CreateAdjacentJoint }, { "med-build-sloppy-adj-joint", 0, CreateSloppyAdjacentJoint }, { "med-build-sloppy-adj-joint-group", 0, CreateSloppyAdjacentJointsGroup }, { "med-build-adj-joints-segment", 0, CreateAdjacentJointsSegment }, { "med-build-adj-joints-all", 0, CreateAdjacentJointsAll }, // In segment.c { "med-segment-bottom", 0, ToggleBottom }, //make_curside_bottom_side }, { "med-segment-show-bottom", 0, ToggleBottom }, // In ksegmove.c { "med-segmove-decrease-heading", 0, DecreaseHeading }, { "med-segmove-increase-heading", 0, IncreaseHeading }, { "med-segmove-decrease-pitch", 0, DecreasePitch }, { "med-segmove-increase-pitch", 0, IncreasePitch }, { "med-segmove-decrease-bank", 0, DecreaseBank }, { "med-segmove-increase-bank", 0, IncreaseBank }, // In ksegsel.c { "med-segsel-next-segment", 0, SelectCurrentSegForward }, { "med-segsel-prev-segment", 0, SelectCurrentSegBackward }, { "med-segsel-next-side", 0, SelectNextSide }, { "med-segsel-prev-side", 0, SelectPrevSide }, { "med-segsel-set-marked", 0, CopySegToMarked }, { "med-segsel-bottom", 0, SelectBottom }, { "med-segsel-front", 0, SelectFront }, { "med-segsel-top", 0, SelectTop }, { "med-segsel-back", 0, SelectBack }, { "med-segsel-left", 0, SelectLeft }, { "med-segsel-right", 0, SelectRight }, // In ksegsize.c { "med-segsize-increase-length", 0, IncreaseSegLength }, { "med-segsize-decrease-length", 0, DecreaseSegLength }, { "med-segsize-decrease-width", 0, DecreaseSegWidth }, { "med-segsize-increase-width", 0, IncreaseSegWidth }, { "med-segsize-increase-height", 0, IncreaseSegHeight }, { "med-segsize-decrease-height", 0, DecreaseSegHeight }, { "med-segsize-increase-length-big", 0, IncreaseSegLengthBig }, { "med-segsize-decrease-length-big", 0, DecreaseSegLengthBig }, { "med-segsize-decrease-width-big", 0, DecreaseSegWidthBig }, { "med-segsize-increase-width-big", 0, IncreaseSegWidthBig }, { "med-segsize-increase-height-big", 0, IncreaseSegHeightBig }, { "med-segsize-decrease-height-big", 0, DecreaseSegHeightBig }, { "med-segsize-toggle-mode", 0, ToggleSegSizeMode }, { "med-segsize-perturb-curside", 0, PerturbCurside }, { "med-segsize-perturb-curside-big", 0, PerturbCursideBig }, { "med-segsize-increase-length-default", 0, IncreaseSegLengthDefault }, { "med-segsize-decrease-length-default", 0, DecreaseSegLengthDefault }, { "med-segsize-increase-width-default", 0, IncreaseSegWidthDefault }, { "med-segsize-decrease-width-default", 0, DecreaseSegWidthDefault }, { "med-segsize-increase-height-default", 0, IncreaseSegHeightDefault }, { "med-segsize-decrease-height-default", 0, DecreaseSegHeightDefault }, // In ktmap.c { "med-tmap-assign", 0, AssignTexture }, { "med-tmap-assign2", 0, AssignTexture2 }, { "med-tmap-clear2", 0, ClearTexture2 }, { "med-tmap-propogate", 0, PropagateTextures }, { "med-tmap-propogate-move", 0, PropagateTexturesMove }, { "med-tmap-propogate-move-uvs", 0, PropagateTexturesMoveUVs }, { "med-tmap-propogate-move-uvs", 0, PropagateTexturesMoveUVs }, { "med-tmap-propogate-uvs", 0, PropagateTexturesUVs }, { "med-tmap-propogate-selected", 0, PropagateTexturesSelected }, // In wall.c { "med-wall-add-blastable", 0, wall_add_blastable }, { "med-wall-add-door", 0, wall_add_door }, { "med-wall-add-closed", 0, wall_add_closed_wall }, { "med-wall-add-external", 0, wall_add_external_wall }, { "med-wall-add-illusion", 0, wall_add_illusion }, { "med-wall-restore-all", 0, wall_restore_all }, { "med-wall-remove", 0, wall_remove }, { "do-wall-dialog", 0, do_wall_dialog }, { "med-link-doors", 0, wall_link_doors }, { "med-unlink-door", 0, wall_unlink_door }, { "check-walls", 0, check_walls }, { "delete-all-walls", 0, delete_all_walls }, // In centers.c { "do-centers-dialog", 0, do_centers_dialog }, // In switch.c //{ "med-trigger-add-damage", 0, trigger_add_damage }, //{ "med-trigger-add-exit", 0, trigger_add_exit }, //{ "med-trigger-control", 0, trigger_control }, //{ "med-trigger-remove", 0, trigger_remove }, //{ "med-bind-wall-to-control", 0, bind_wall_to_control_trigger }, { "do-trigger-dialog", 0, do_trigger_dialog }, //--//// In macro.c //--//{ "med-macro-menu", 0, MacroMenu }, //--//{ "med-macro-play-fast", 0, MacroPlayFast }, //--//{ "med-macro-play-normal", 0, MacroPlayNormal }, //--//{ "med-macro-record-all", 0, MacroRecordAll }, //--//{ "med-macro-record-keys", 0, MacroRecordKeys }, //--//{ "med-macro-save", 0, MacroSave }, //--//{ "med-macro-load", 0, MacroLoad }, // In editor.c { "med-update", 0, medlisp_update_screen }, { "med-segment-add", 0, AttachSegment }, { "med-segment-delete", 0, medlisp_delete_segment }, { "med-segment-scale", 3, medlisp_scale_segment }, { "med-segment-rotate", 3, medlisp_rotate_segment }, { "med-dos-shell", 0, DosShell }, //{ "med-lisp-call", 0, CallLisp }, { "med-editor-exit", 0, ExitEditor }, { "med-segment-exchange", 0, ExchangeMarkandCurseg }, { "med-segment-mark", 0, CopySegToMarked }, { "med-about", 0, ShowAbout }, #ifndef NDEBUG { "med-mark-start", 0, MarkStart }, { "med-mark-end", 0, MarkEnd }, #endif // In group.c { "med-group-load", 0, LoadGroup }, { "med-group-save", 0, SaveGroup }, { "med-move-group", 0, MoveGroup }, { "med-copy-group", 0, CopyGroup }, { "med-rotate-group", 0, RotateGroup }, { "med-segment-add-new", 0, AttachSegmentNew }, { "med-mark-groupseg", 0, MarkGroupSegment }, { "med-next-group", 0, NextGroup }, { "med-prev-group", 0, PrevGroup }, { "med-delete-group", 0, DeleteGroup }, { "med-create-group", 0, CreateGroup }, { "med-ungroup-segment", 0, UngroupSegment }, { "med-group-segment", 0, GroupSegment }, { "med-degroup-group", 0, Degroup }, { "med-subtract-from-group", 0, SubtractFromGroup }, // In autosave.c { "med-autosave-undo", 0, UndoCommand }, { "med-autosave-toggle", 0, ToggleAutosave }, // In texture.c { "med-tass-flip-x", 0, TexFlipX }, { "med-tass-flip-y", 0, TexFlipY }, { "med-tass-slide-up", 0, TexSlideUp }, { "med-tass-slide-left", 0, TexSlideLeft }, { "med-tass-set-default", 0, TexSetDefault }, { "med-tass-slide-right", 0, TexSlideRight }, { "med-tass-rotate-left", 0, TexRotateLeft }, { "med-tass-slide-down", 0, TexSlideDown }, { "med-tass-stretch-down", 0, TexStretchDown }, { "med-tass-stretch-up", 0, TexStretchUp }, { "med-tass-rotate-right", 0, TexRotateRight }, { "med-tass-select-active-edge", 0, TexSelectActiveEdge }, { "med-tass-rotate-90-degrees", 0, TexRotate90Degrees }, { "med-tass-increase-tiling", 0, TexIncreaseTiling }, { "med-tass-decrease-tiling", 0, TexDecreaseTiling }, { "med-tass-slide-up-big", 0, TexSlideUpBig }, { "med-tass-slide-left-big", 0, TexSlideLeftBig }, { "med-tass-slide-right-big", 0, TexSlideRightBig }, { "med-tass-rotate-left-big", 0, TexRotateLeftBig }, { "med-tass-slide-down-big", 0, TexSlideDownBig }, { "med-tass-rotate-right-big", 0, TexRotateRightBig }, // In eobject.c { "med-obj-set-player", 0, SetPlayerPosition }, { "med-obj-place-object", 0, ObjectPlaceObject }, { "med-obj-place-object-tmap", 0, ObjectPlaceObjectTmap }, { "med-obj-move-nearer", 0, ObjectMoveNearer }, { "med-obj-move-further", 0, ObjectMoveFurther }, { "med-obj-delete-object", 0, ObjectDelete }, { "med-obj-move-forward", 0, ObjectMoveForward }, { "med-obj-move-left", 0, ObjectMoveLeft }, { "med-obj-set-default", 0, ObjectSetDefault }, { "med-obj-move-right", 0, ObjectMoveRight }, { "med-obj-move-back", 0, ObjectMoveBack }, { "med-obj-move-down", 0, ObjectMoveDown }, { "med-obj-move-up", 0, ObjectMoveUp }, { "med-obj-select-next-in-segment", 0, ObjectSelectNextinSegment }, { "med-obj-decrease-bank", 0, ObjectDecreaseBank }, { "med-obj-increase-bank", 0, ObjectIncreaseBank }, { "med-obj-decrease-pitch", 0, ObjectDecreasePitch }, { "med-obj-increase-pitch", 0, ObjectIncreasePitch }, { "med-obj-decrease-heading", 0, ObjectDecreaseHeading }, { "med-obj-increase-heading", 0, ObjectIncreaseHeading }, { "med-obj-decrease-bank-big", 0, ObjectDecreaseBankBig }, { "med-obj-increase-bank-big", 0, ObjectIncreaseBankBig }, { "med-obj-decrease-pitch-big", 0, ObjectDecreasePitchBig }, { "med-obj-increase-pitch-big", 0, ObjectIncreasePitchBig }, { "med-obj-decrease-heading-big", 0, ObjectDecreaseHeadingBig }, { "med-obj-increase-heading-big", 0, ObjectIncreaseHeadingBig }, { "med-obj-reset", 0, ObjectResetObject }, { "med-obj-flip", 0, ObjectFlipObject }, { "med-obj-make-coop", 0, ObjectMakeCoop }, //{ "med-obj-place-hostage", 0, ObjectPlaceHostage }, // In objpage.c { "med-obj-select-next-type", 0, objpage_goto_next_object }, // In elight.c { "med-light-select-next-vertex", 0, LightSelectNextVertex }, { "med-light-select-next-edge", 0, LightSelectNextEdge }, { "med-light-copy-intensity-side", 0, LightCopyIntensity }, { "med-light-copy-intensity-segment", 0, LightCopyIntensitySegment }, { "med-light-decrease-light-vertex", 0, LightDecreaseLightVertex }, { "med-light-increase-light-vertex", 0, LightIncreaseLightVertex }, { "med-light-decrease-light-side", 0, LightDecreaseLightSide }, { "med-light-increase-light-side", 0, LightIncreaseLightSide }, { "med-light-decrease-light-segment", 0, LightDecreaseLightSegment }, { "med-light-increase-light-segment", 0, LightIncreaseLightSegment }, { "med-light-set-maximum", 0, LightSetMaximum }, { "med-light-set-default", 0, LightSetDefault }, { "med-light-assign-default-all", 0, LightSetDefaultAll }, { "med-light-ambient-lighting", 0, LightAmbientLighting }, // In seguvs.c { "med-seguvs-fix-bogus-uvs-on-side", 0, fix_bogus_uvs_on_side}, { "med-seguvs-fix-bogus-uvs-all", 0, fix_bogus_uvs_all}, { "med-seguvs-smooth-lighting-all", 0, set_average_light_on_all}, { "med-seguvs-smooth-lighting-all-quick", 0, set_average_light_on_all_quick}, { "med-seguvs-smooth-lighting", 0, set_average_light_on_curside}, // Miscellaneous, please neaten and catagorize me! { "med-increase-draw-depth", 0, IncreaseDrawDepth }, { "med-decrease-draw-depth", 0, DecreaseDrawDepth }, { "med-goto-main-menu", 0, GotoMainMenu }, { "med-goto-game-screen", 0, GotoGameScreen }, { "med-drop-into-debugger", 0, DropIntoDebugger }, // { "med-sync-large-view", 0, SyncLargeView }, { "med-create-default-new-segment", 0, CreateDefaultNewSegment }, { "med-create-default-new-segment-and-attach", 0, CreateDefaultNewSegmentandAttach }, { "med-clear-selected-list", 0, ClearSelectedList }, { "med-clear-found-list", 0, ClearFoundList }, { "med-sort-selected-list", 0, SortSelectedList }, { "med-set-player-from-curseg", 0, SetPlayerFromCursegAndRotate }, { "med-set-player-from-curseg-minus-one", 0, SetPlayerFromCursegMinusOne }, { "med-find-concave-segs", 0, FindConcaveSegs }, { "med-select-next-found-seg", 0, SelectNextFoundSeg }, { "med-select-prev-found-seg", 0, SelectPreviousFoundSeg }, { "med-stop-slew", 0, slew_stop }, //{ "med-reset-orientation", 0, do_reset_orient }, { "med-game-zoom-out", 0, GameZoomOut }, { "med-game-zoom-in", 0, GameZoomIn }, { "med-keypad-goto-prev", 0, med_keypad_goto_prev }, { "med-keypad-goto-next", 0, med_keypad_goto_next }, { "med-keypad-goto", 1, med_keypad_goto }, // John's temporary function page stuff // { "med-set-function-page", 1, medtmp_set_page }, // In fuelcen.c { "med-fuelcen-create", 0, fuelcen_create_from_curseg }, { "med-repaircen-create", 0, repaircen_create_from_curseg }, { "med-controlcen-create", 0, controlcen_create_from_curseg }, { "med-robotmaker-create", 0, robotmaker_create_from_curseg }, { "med-fuelcen-reset-all", 0, fuelcen_reset_all }, { "med-fuelcen-delete", 0, fuelcen_delete_from_curseg }, // In robot.c { "do-robot-dialog", 0, do_robot_dialog }, { "do-object-dialog", 0, do_object_dialog }, { "do-hostage-dialog", 0, do_hostage_dialog }, // In gamesavec { "rename-level", 0, get_level_name }, // The terminating marker { NULL, 0, NULL } }; void init_med_functions() { func_init(med_functions, (sizeof(med_functions)/sizeof(FUNCTION))-1 ); } dxx-rebirth-0.58.1-d1x/editor/kgame.c000066400000000000000000000100661217717257200172730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Game Loading editor functions * */ #include #include #include "inferno.h" #include "editor.h" #include "ui.h" #include "game.h" #include "gamesave.h" #include "gameseq.h" char game_filename[PATH_MAX] = "*.RDL"; extern void checkforext( char * f, char *ext ); void checkforgamext( char * f ) { int i; for (i=1; ipos; Perm_player_orient = ConsoleObject->orient; Perm_player_segnum = ConsoleObject->segnum; editor_status("Player initial position set"); return 0; } // Save game // returns 1 if successful // returns 0 if unsuccessful int SaveGameData() { char Message[200]; if (gamestate_not_restored) { sprintf( Message, "Game State has not been restored...\nContinue?\n"); if (ui_messagebox( -2, -2, 2, Message, "NO", "Yes" )==1) return 0; } if (ui_get_filename( game_filename, "*.RDL", "SAVE GAME" )) { int saved_flag; vms_vector save_pos = ConsoleObject->pos; vms_matrix save_orient = ConsoleObject->orient; int save_segnum = ConsoleObject->segnum; checkforgamext(game_filename); if (Perm_player_segnum > Highest_segment_index) Perm_player_segnum = -1; if (Perm_player_segnum!=-1) { if (get_seg_masks(&Perm_player_position, Perm_player_segnum, 0, __FILE__, __LINE__).centermask == 0) { ConsoleObject->pos = Perm_player_position; obj_relink(ConsoleObject-Objects,Perm_player_segnum); ConsoleObject->orient = Perm_player_orient; } else Perm_player_segnum=-1; //position was bogus } saved_flag=save_level(game_filename); if (Perm_player_segnum!=-1) { int found_save_segnum; if (save_segnum > Highest_segment_index) save_segnum = 0; ConsoleObject->pos = save_pos; found_save_segnum = find_point_seg(&save_pos,save_segnum); if (found_save_segnum == -1) { compute_segment_center(&save_pos, &(Segments[save_segnum])); found_save_segnum = save_segnum; } obj_relink(ConsoleObject-Objects,found_save_segnum); ConsoleObject->orient = save_orient; } if (saved_flag) return 0; mine_changed = 0; } return 1; } // returns 1 if successful // returns 0 if unsuccessful int LoadGameData() { if (SafetyCheck()) { if (ui_get_filename( game_filename, "*.RDL", "LOAD GAME" )) { checkforgamext(game_filename); if (load_level(game_filename)) return 0; Current_level_num = 0; //not a real level gamestate_not_restored = 0; Update_flags = UF_WORLD_CHANGED; Perm_player_position = ConsoleObject->pos; Perm_player_orient = ConsoleObject->orient; Perm_player_segnum = ConsoleObject->segnum; } } return 1; } //called whenever a new mine is created, so new mine doesn't get name //of last saved mine as default void ResetFilename() { strcpy(game_filename,"*.LVL"); } dxx-rebirth-0.58.1-d1x/editor/khelp.c000066400000000000000000000134411217717257200173120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for showing help. * */ #include "inferno.h" #include "editor.h" #include "ui.h" static char MainHelpText[] = "\nMED General Functions\n\n" \ "SPACEBAR Full Redraw\n" \ "BACKSPACE Drop into debugger\n\n" \ "A Attach a segment\n" \ "D Delete current segment\n\n" \ "F Toggle to game\n" \ "G or S Go to game (Toggle screen)\n\n" \ "ALT-C Create new mine\n" \ "ALT-S Save mine\n" \ "ALT-L Load mine\n"\ "ESC Exit editor\n"\ "ALT-Q/CTRL-Q/SHIFT-Q also Exit editor\n"; static char SegmentHelpText[] = "MED Segment Functions\n\n" \ "ALT-B Create Bridge from current to marked segment\n" \ "ALT-E Exchange current and marked segments\n" \ "ALT-J Create Joint between current and marked segments\n" \ "ALT-SHIFT-J Create Joint on current side and adjacent segments\n" \ "ALT-CTRL-J Create Joint on current segment and adjacent segments\n" \ "ALT-CTRL-SHIFT-J Create Joints on all adjacent segments\n" \ "ALT-M Mark current segment and side\n" \ "ALT-N Create default segment for New_segment\n" \ "CTRL-A Toggle - Draw all segments/Draw connected segments\n" \ "CTRL-C Clear selected list\n" \ "CTRL-D Toggle display of coordinate axes\n" \ "CTRL-S Advance to segment through Curside\n" \ "ALT-T Assign Texture to current side\n" \ "CTRL-P Propogate Textures\n" \ "CTRL-SHIFT-P Propogate Textures on Selected segments\n" \ "CTRL-SHIFT-S Advance to segment opposite Curside\n" \ "CTRL-F Select next side\n" \ "CTRL-SHIFT-F Select previous side\n"; static char KeyPadHelpText[] = "MED KeyPad Functions\n\n" \ "SHIFT-KEYPAD FUNCTIONS (Change direction vector of segment)\n" \ "----------------------\n" \ "(7) 8 Decrease Pitch (9)\n" \ " 4 Decrease Heading (5) 6 Increase Heading\n" \ " 1 Decrease Bank 2 Increase Pitch 3 Increase Bank\n\n" \ "CTRL-KEYPAD FUNCTIONS (Change size/shape of segment)\n" \ "---------------------\n" \ "(7) 8 Increase Length 9 Increase Height\n" \ " 4 Decrease Width (5) 6 Increase Width\n" \ "(1) 2 Decrease Length 3 Decrease Height\n"\ "\nIn addition, CTRL-SHIFT-KEYPAD Changes size at x5 rate as above\n"; char ViewHelpText[] = "MED View Changing Functions\n\n" \ "ALT-V Change to orthogonal view (1,2,3)\n" \ "CTRL-V Toggle view to current segment\n" \ "MINUS (-) Zoom in\n" \ "EQUAL (=) Zoom out\n" \ "SHIFT-MINUS Decrease viewer distance\n" \ "SHIFT-EQUAL Increase viewer distance\n" \ "\n* Holding the Ctrl key and moving the mouse will change\n" \ "the viewer's orientation in the main window."; //"CTRL-MINUS Decreases drawing depth\n" //"CTRL-EQUAL Increases drawing depth\n" static char GameHelpText[] = "MED Game Screen Functions\n\n" \ "KEYPAD FUNCTIONS (Moves in game screen)\n" \ "----------------\n" \ "(7) 8 Move Forward (9)\n" \ " 4 Decrease Heading 5 Complete Stop 6 Increase Heading\n" \ " 1 Decrease Bank 2 Move Backward 3 Increase Bank\n\n" \ "[ Decreases Pitch\n" \ "] Increases Pitch\n" \ "C Set Player from Current segment\n" \ "L Toggle Lock Step\n" \ "O Toggle Outline Mode\n" \ "SHIFT-C Set PLayer from Current segment-1\n" \ "SHIFT-L Toggle Lighting effect\n" \ "NUMLOCK Reset orientation\n" \ "PAD DIVIDE (/) Game Zoom out\n" \ "PAD MULTIPLY (*) Game Zoom In\n"; static char CurveHelpText[] = "MED Curve Generation Functions\n\n" \ "ALT-F10 Generate curve\n" \ "F8 Delete curve\n" \ "F11 'Set' curve\n" \ "F9 Decrease r1 vector\n" \ "SHIFT-F9 Increase r1 vector\n" \ "F10 Decrease r4 vector\n" \ "SHIFT-F10 Increase r4 vector\n"; static char MacrosHelpText[] = "MED Macros Functions\n\n" \ "CTRL-INSERT Play fast\n" \ "CTRL-DELETE Play normal\n" \ "CTRL-HOME Record all\n" \ "CTRL-END Record keys\n" \ "CTRL-PAGEUP Save Macro\n" \ "CTRL-PAGEDOWN Load Macro\n"; int DoHelp() { int help_key = 2; int more_key = 2; while (help_key > 1) { help_key = ui_messagebox( -2, -2, 5, MainHelpText, "Ok", "Segment", "Keypad", "View", "More"); if (help_key == 2) ui_messagebox( -2, -2, 1, SegmentHelpText, "Ok" ); if (help_key == 3) ui_messagebox( -2, -2, 1, KeyPadHelpText, "Ok" ); if (help_key == 4) ui_messagebox( -2, -2, 1, ViewHelpText, "Ok" ); if (help_key == 5) { more_key = ui_messagebox( -2, -2, 4, MainHelpText, "Back", "Curve", "Macro", "Game"); if (more_key == 2) ui_messagebox( -2, -2, 1, CurveHelpText, "Ok" ); if (help_key == 3) ui_messagebox( -2, -2, 1, MacrosHelpText, "Ok" ); if (help_key == 4) ui_messagebox( -2, -2, 1, GameHelpText, "Ok" ); } } return 1; } dxx-rebirth-0.58.1-d1x/editor/kmine.c000066400000000000000000000142241217717257200173120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to change entire mines. * */ #include #include #include #include "dxxerror.h" #include "strutil.h" #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "ui.h" #include "texpage.h" // For texpage_goto_first #include "segment.h" #include "kdefs.h" #include "info.h" #include "game.h" #include "gameseq.h" #include "object.h" #define MINESAVE_CRIPPLED 0 char mine_filename[PATH_MAX] = "*.MIN"; char sit_filename[PATH_MAX] = "*.SIT"; #define MAX_NAME_LENGTH PATH_MAX // See if filename f contains an extent. If not, add extent ext. void checkforext( char * f, char *ext ) { int i; for (i=1; ipos.x,(unsigned int) ConsoleObject->pos.y,(unsigned int) ConsoleObject->pos.z); // Write player orientation. PHYSFSX_printf(SaveFile, "%8x %8x %8x\n",(unsigned int) ConsoleObject->orient.rvec.x,(unsigned int) ConsoleObject->orient.rvec.y,(unsigned int) ConsoleObject->orient.rvec.z); PHYSFSX_printf(SaveFile, "%8x %8x %8x\n",(unsigned int) ConsoleObject->orient.uvec.x,(unsigned int) ConsoleObject->orient.uvec.y,(unsigned int) ConsoleObject->orient.uvec.z); PHYSFSX_printf(SaveFile, "%8x %8x %8x\n",(unsigned int) ConsoleObject->orient.fvec.x,(unsigned int) ConsoleObject->orient.fvec.y,(unsigned int) ConsoleObject->orient.fvec.z); PHYSFSX_printf(SaveFile, "%i\n", ConsoleObject->segnum); PHYSFS_close( SaveFile); return 1; } // ----------------------------------------------------------------------------- int SaveSituation(void) { if (ui_get_filename( sit_filename, "*.SIT", "Save Situation" )) { set_extension(sit_filename, "MIN"); if (med_save_mine(sit_filename)) { return 0; } set_extension(sit_filename, "SIT"); if (med_save_situation(sit_filename)) return 0; } return 1; } // ----------------------------------------------------------------------------- // Load a situation file which consists of x,y,z, orientation matrix, mine name. int LoadSituation(void) { if (SafetyCheck()) { if (ui_get_filename( sit_filename, "*.sit", "Load Situation" )) { checkforext(sit_filename, "SIT"); if (med_load_situation(sit_filename)) return 0; // set_view_target_from_segment(Cursegp); Update_flags = UF_WORLD_CHANGED; // SetPlayerFromCurseg(); med_compress_mine(); init_info = 1; mine_changed = 0; } } return 1; } dxx-rebirth-0.58.1-d1x/editor/ksegmove.c000066400000000000000000000040231217717257200200230ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for moving segments. * */ //#include //#include //#include //#include #include "inferno.h" #include "editor.h" #include "editor/esegment.h" // -- old -- int SegOrientCommon(fixang *ang, fix val) // -- old -- { // -- old -- *ang += val; // -- old -- med_rotate_segment_ang(Cursegp,&Seg_orientation); // -- old -- Update_flags |= UF_WORLD_CHANGED; // -- old -- mine_changed = 1; // -- old -- warn_if_concave_segment(Cursegp); // -- old -- return 1; // -- old -- } int SegOrientCommon(fixang *ang, fix val) { Seg_orientation.p = 0; Seg_orientation.b = 0; Seg_orientation.h = 0; *ang += val; rotate_segment_new(&Seg_orientation); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; warn_if_concave_segment(Cursegp); return 1; } // ---------- segment orientation control ---------- int DecreaseHeading() { // decrease heading return SegOrientCommon(&Seg_orientation.h,-512); } int IncreaseHeading() { return SegOrientCommon(&Seg_orientation.h,+512); } int DecreasePitch() { return SegOrientCommon(&Seg_orientation.p,-512); } int IncreasePitch() { return SegOrientCommon(&Seg_orientation.p,+512); } int DecreaseBank() { return SegOrientCommon(&Seg_orientation.b,-512); } int IncreaseBank() { return SegOrientCommon(&Seg_orientation.b,+512); } dxx-rebirth-0.58.1-d1x/editor/ksegsel.c000066400000000000000000000122471217717257200176470ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for selecting segments * */ #include #include "inferno.h" #include "editor/editor.h" #include "editor/esegment.h" // --------------------------------------------------------------------------------------- // Select previous segment. // If there is a connection on the side opposite to the current side, then choose that segment. // If there is no connecting segment on the opposite face, try any segment. void get_previous_segment(int curseg_num, int curside,int *newseg_num, int *newside) { int s; *newseg_num = curseg_num; if (IS_CHILD(Segments[curseg_num].children[(int)Side_opposite[curside]])) *newseg_num = Segments[curseg_num].children[(int)Side_opposite[curside]]; else // no segment on opposite face, connect to anything for (s=0; s= MAX_SIDES_PER_SEGMENT) Curside = 0; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectPrevSide() { if (--Curside < 0) Curside = MAX_SIDES_PER_SEGMENT-1; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } // ---------- Copy current segment and side to marked segment and side ---------- int CopySegToMarked() { autosave_mine(mine_filename); strcpy(undo_status[Autosave_count], "Mark Segment UNDONE."); Markedsegp = Cursegp; Markedside = Curside; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } // ---------- select absolute face on segment ---------- int SelectBottom() { Curside = WBOTTOM; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectFront() { Curside = WFRONT; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectTop() { Curside = WTOP; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectBack() { Curside = WBACK; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectLeft() { Curside = WLEFT; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } int SelectRight() { Curside = WRIGHT; Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; return 1; } dxx-rebirth-0.58.1-d1x/editor/ksegsize.c000066400000000000000000000261031217717257200200320ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for sizing segments * */ #include #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "gameseg.h" #define XDIM 0 #define YDIM 1 #define ZDIM 2 #define MAX_MODIFIED_VERTICES 32 int Modified_vertices[MAX_MODIFIED_VERTICES]; int Modified_vertex_index = 0; // ------------------------------------------------------------------------------------------ void validate_modified_segments(void) { int v,w,v0,seg; char modified_segments[MAX_SEGMENTS]; for (v=0; v<=Highest_segment_index; v++) modified_segments[v] = 0; for (v=0; vx += fixmul(vp->x,scale_factor)/2; vertp->y += fixmul(vp->y,scale_factor)/2; vertp->z += fixmul(vp->z,scale_factor)/2; Assert(Modified_vertex_index < MAX_MODIFIED_VERTICES); Modified_vertices[Modified_vertex_index++] = vertex_ind; } // ------------------------------------------------------------------------------------------ void scale_vert(segment *sp, int vertex_ind, vms_vector *vp, fix scale_factor) { switch (SegSizeMode) { case SEGSIZEMODE_FREE: if (is_free_vertex(vertex_ind)) scale_vert_aux(vertex_ind, vp, scale_factor); break; case SEGSIZEMODE_ALL: scale_vert_aux(vertex_ind, vp, scale_factor); break; case SEGSIZEMODE_CURSIDE: { int v; for (v=0; v<4; v++) if (sp->verts[Side_to_verts[Curside][v]] == vertex_ind) scale_vert_aux(vertex_ind, vp, scale_factor); break; } case SEGSIZEMODE_EDGE: { int v; for (v=0; v<2; v++) if (sp->verts[Side_to_verts[Curside][(Curedge+v)%4]] == vertex_ind) scale_vert_aux(vertex_ind, vp, scale_factor); break; } case SEGSIZEMODE_VERTEX: if (sp->verts[Side_to_verts[Curside][Curvert]] == vertex_ind) scale_vert_aux(vertex_ind, vp, scale_factor); break; default: Error("Unsupported SegSizeMode in ksegsize.c/scale_vert = %i\n", SegSizeMode); } } // ------------------------------------------------------------------------------------------ void scale_free_verts(segment *sp, vms_vector *vp, int side, fix scale_factor) { int v; sbyte *verts; int vertex_ind; verts = Side_to_verts[side]; for (v=0; v<4; v++) { vertex_ind = sp->verts[(int) verts[v]]; if (SegSizeMode || is_free_vertex(vertex_ind)) scale_vert(sp, vertex_ind, vp, scale_factor); } } // ----------------------------------------------------------------------------- // Make segment *sp bigger in dimension dimension by amount amount. void med_scale_segment_new(segment *sp, int dimension, fix amount) { vms_matrix mat; Modified_vertex_index = 0; med_extract_matrix_from_segment(sp, &mat); switch (dimension) { case XDIM: scale_free_verts(sp, &mat.rvec, WLEFT, -amount); scale_free_verts(sp, &mat.rvec, WRIGHT, +amount); break; case YDIM: scale_free_verts(sp, &mat.uvec, WBOTTOM, -amount); scale_free_verts(sp, &mat.uvec, WTOP, +amount); break; case ZDIM: scale_free_verts(sp, &mat.fvec, WFRONT, -amount); scale_free_verts(sp, &mat.fvec, WBACK, +amount); break; } validate_modified_segments(); } // ------------------------------------------------------------------------------------------ // Extract a vector from a segment. The vector goes from the start face to the end face. // The point on each face is the average of the four points forming the face. void extract_vector_from_segment_side(segment *sp, int side, vms_vector *vp, int vla, int vlb, int vra, int vrb) { vms_vector v1, v2; vm_vec_sub(&v1,&Vertices[sp->verts[Side_to_verts[side][vra]]],&Vertices[sp->verts[Side_to_verts[side][vla]]]); vm_vec_sub(&v2,&Vertices[sp->verts[Side_to_verts[side][vrb]]],&Vertices[sp->verts[Side_to_verts[side][vlb]]]); vm_vec_add(vp, &v1, &v2); vm_vec_scale(vp, F1_0/2); } // ------------------------------------------------------------------------------------------ // Extract the right vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the left face of the segment // to the center of the right face of the segment. void med_extract_right_vector_from_segment_side(segment *sp, int sidenum, vms_vector *vp) { extract_vector_from_segment_side(sp, sidenum, vp, 3, 2, 0, 1); } // ------------------------------------------------------------------------------------------ // Extract the up vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the bottom face of the segment // to the center of the top face of the segment. void med_extract_up_vector_from_segment_side(segment *sp, int sidenum, vms_vector *vp) { extract_vector_from_segment_side(sp, sidenum, vp, 1, 2, 0, 3); } // ----------------------------------------------------------------------------- // Increase the size of Cursegp in dimension dimension by amount int segsize_common(int dimension, fix amount) { int i; int propagated[MAX_SIDES_PER_SEGMENT]; vms_vector uvec, rvec, fvec, scalevec; Degenerate_segment_found = 0; med_scale_segment_new(Cursegp, dimension, amount); med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec); med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec); extract_forward_vector_from_segment(Cursegp, &fvec); scalevec.x = vm_vec_mag(&rvec); scalevec.y = vm_vec_mag(&uvec); scalevec.z = vm_vec_mag(&fvec); if (Degenerate_segment_found) { Degenerate_segment_found = 0; editor_status("Applying scale would create degenerate segments. Aborting scale."); med_scale_segment_new(Cursegp, dimension, -amount); return 1; } med_create_new_segment(&scalevec); // For all segments to which Cursegp is connected, propagate tmap (uv coordinates) from the connected // segment back to Cursegp. This will meaningfully propagate uv coordinates to all sides which havve // an incident edge. It will also do some sides more than once. And it is probably just not what you want. for (i=0; ichildren[i])) { int s; for (s=0; schildren[i]],Cursegp,1); } // Now, for all sides that were not adjacent to another side, and therefore did not get tmaps // propagated to them, treat as a back side. for (i=0; i SEGSIZEMODE_MAX) SegSizeMode = SEGSIZEMODE_MIN; return 1; } // --------------------------------------------------------------------------- int PerturbCursideCommon(fix amount) { int saveSegSizeMode = SegSizeMode; vms_vector fvec, rvec, uvec; fix fmag, rmag, umag; int v; SegSizeMode = SEGSIZEMODE_CURSIDE; Modified_vertex_index = 0; extract_forward_vector_from_segment(Cursegp, &fvec); extract_right_vector_from_segment(Cursegp, &rvec); extract_up_vector_from_segment(Cursegp, &uvec); fmag = vm_vec_mag(&fvec); rmag = vm_vec_mag(&rvec); umag = vm_vec_mag(&uvec); for (v=0; v<4; v++) { vms_vector perturb_vec; perturb_vec.x = fixmul(rmag, d_rand()*2 - 32767); perturb_vec.y = fixmul(umag, d_rand()*2 - 32767); perturb_vec.z = fixmul(fmag, d_rand()*2 - 32767); scale_vert(Cursegp, Cursegp->verts[Side_to_verts[Curside][v]], &perturb_vec, amount); } // validate_segment(Cursegp); // if (SegSizeMode) { // for (i=0; ichildren[i] != -1) // validate_segment(&Segments[Cursegp->children[i]]); // } validate_modified_segments(); SegSizeMode = saveSegSizeMode; Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; return 1; } // --------------------------------------------------------------------------- int PerturbCurside(void) { PerturbCursideCommon(F1_0/10); return 1; } // --------------------------------------------------------------------------- int PerturbCursideBig(void) { PerturbCursideCommon(F1_0/2); return 1; } dxx-rebirth-0.58.1-d1x/editor/ktmap.c000066400000000000000000000115771217717257200173330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Texture map key bindings. * */ #include #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "kdefs.h" // Assign CurrentTexture to Curside in *Cursegp int AssignTexture(void) { autosave_mine( mine_filename ); strcpy(undo_status[Autosave_count], "Assign Texture UNDONE."); Cursegp->sides[Curside].tmap_num = CurrentTexture; New_segment.sides[Curside].tmap_num = CurrentTexture; // propagate_light_intensity(Cursegp, Curside, CurrentTexture, 0); Update_flags |= UF_WORLD_CHANGED; return 1; } // Assign CurrentTexture to Curside in *Cursegp int AssignTexture2(void) { int texnum, orient, ctexnum, newtexnum; autosave_mine( mine_filename ); strcpy(undo_status[Autosave_count], "Assign Texture 2 UNDONE."); texnum = Cursegp->sides[Curside].tmap_num2 & 0x3FFF; orient = ((Cursegp->sides[Curside].tmap_num2 & 0xC000) >> 14) & 3; ctexnum = CurrentTexture; if ( ctexnum == texnum ) { orient = (orient+1) & 3; newtexnum = (orient<<14) | texnum; } else { newtexnum = ctexnum; } Cursegp->sides[Curside].tmap_num2 = newtexnum; New_segment.sides[Curside].tmap_num2 = newtexnum; Update_flags |= UF_WORLD_CHANGED; return 1; } int ClearTexture2(void) { autosave_mine( mine_filename ); strcpy(undo_status[Autosave_count], "Clear Texture 2 UNDONE."); Cursegp->sides[Curside].tmap_num2 = 0; New_segment.sides[Curside].tmap_num2 = 0; Update_flags |= UF_WORLD_CHANGED; return 1; } // -------------------------------------------------------------------------------------------------- // Propagate textures from Cursegp through Curside. // If uv_flag !0, then only propagate uv coordinates (if 0, then propagate textures as well) // If move_flag !0, then move forward to new segment after propagation, else don't int propagate_textures_common(int uv_flag, int move_flag) { autosave_mine( mine_filename ); strcpy(undo_status[Autosave_count], "Propogate Textures UNDONE."); if (IS_CHILD(Cursegp->children[Curside])) med_propagate_tmaps_to_segments(Cursegp, &Segments[Cursegp->children[Curside]], uv_flag); if (move_flag) SelectCurrentSegForward(); Update_flags |= UF_WORLD_CHANGED; return 1; } // Propagate texture maps from current segment, through current side int PropagateTextures(void) { return propagate_textures_common(0, 0); } // Propagate texture maps from current segment, through current side int PropagateTexturesUVs(void) { return propagate_textures_common(-1, 0); } // Propagate texture maps from current segment, through current side // And move to that segment. int PropagateTexturesMove(void) { return propagate_textures_common(0, 1); } // Propagate uv coordinate from current segment, through current side // And move to that segment. int PropagateTexturesMoveUVs(void) { return propagate_textures_common(-1, 1); } // ------------------------------------------------------------------------------------- int is_selected_segment(int segnum) { int i; for (i=0; ichildren[side])) { while ((!Been_visited[sp->children[side]]) && is_selected_segment(sp->children[side])) { med_propagate_tmaps_to_segments(sp,&Segments[sp->children[side]],0); pts_aux(&Segments[sp->children[side]]); } } } } // ------------------------------------------------------------------------------------- // Propagate texture maps from current segment recursively exploring all children, to all segments in Selected_list // until a segment not in Selected_list is reached. int PropagateTexturesSelected(void) { int i; autosave_mine( mine_filename ); strcpy(undo_status[Autosave_count], "Propogate Textures Selected UNDONE."); for (i=0; iev_zoom = fixmul(current_view->ev_zoom,62259); current_view->ev_changed = 1; return 1; } int ZoomOut() { if (!current_view) return 0.0; current_view->ev_zoom = fixmul(current_view->ev_zoom,68985); current_view->ev_changed = 1; return 1; } // ---------- distance-of-viewer control on current window ---------- int MoveCloser() { if (!current_view) return 0.0; current_view->ev_dist = fixmul(current_view->ev_dist,62259); current_view->ev_changed = 1; return 1; } int MoveAway() { if (!current_view) return 0.0; current_view->ev_dist = fixmul(current_view->ev_dist,68985); current_view->ev_changed = 1; return 1; } // ---------- Toggle chase mode. ---------- int ToggleChaseMode() { Funky_chase_mode = !Funky_chase_mode; set_view_target_from_segment(Cursegp); if (Funky_chase_mode == 1) { diagnostic_message("Chase mode ON."); } if (Funky_chase_mode == 0) { diagnostic_message("Chase mode OFF."); } return Funky_chase_mode; } dxx-rebirth-0.58.1-d1x/editor/med.c000066400000000000000000001116531217717257200167600ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Editor loop for Inferno * */ //#define DEMO 1 #define DIAGNOSTIC_MESSAGE_MAX 90 #define EDITOR_STATUS_MESSAGE_DURATION 4 // Shows for 3+..4 seconds #include #include #include #include #include #include "inferno.h" #include "segment.h" #include "gr.h" #include "palette.h" #include "event.h" #include "window.h" #include "messagebox.h" #include "ui.h" #include "editor.h" #include "editor/esegment.h" #include "gamesave.h" #include "gameseg.h" #include "key.h" #include "kconfig.h" #include "mouse.h" #include "dxxerror.h" #include "kfuncs.h" #include "macro.h" #ifdef INCLUDE_XLISP #include "medlisp.h" #endif #include "u_mem.h" #include "physfsx.h" #include "render.h" #include "game.h" #include "gamefont.h" #include "menu.h" #include "slew.h" #include "kdefs.h" #include "func.h" #include "textures.h" #include "screens.h" #include "texmap.h" #include "object.h" #include "effects.h" #include "wall.h" #include "info.h" #include "ai.h" #include "console.h" #include "texpage.h" // Textue selection paging stuff #include "objpage.h" // Object selection paging stuff #include "medmisc.h" #include "meddraw.h" #include "medsel.h" #include "medrobot.h" #include "medwall.h" #include "eswitch.h" #include "ehostage.h" #include "centers.h" #include "fuelcen.h" #include "gameseq.h" #include "newmenu.h" //#define _MARK_ON 1 //#include //should come after inferno.h to get mark setting //Not included here. #define COMPRESS_INTERVAL 5 // seconds //char *undo_status[128]; int initializing; //these are instances of canvases, pointed to by variables below grs_canvas _canv_editor_game, _canv_editor; //the game on the editor screen, the canvas that the editor writes to //these are pointers to our canvases grs_canvas *Canv_editor; //the editor screen grs_canvas *Canv_editor_game=&_canv_editor_game; //the game on the editor screen window *Pad_info; // Keypad text grs_font *editor_font=NULL; //where the editor is looking vms_vector Ed_view_target=ZERO_VECTOR; int gamestate_not_restored = 0; UI_DIALOG * EditorWindow = NULL; int Large_view_index = -1; UI_GADGET_USERBOX * GameViewBox; UI_GADGET_USERBOX * LargeViewBox; UI_GADGET_USERBOX * GroupViewBox; #if ORTHO_VIEWS UI_GADGET_USERBOX * TopViewBox; UI_GADGET_USERBOX * FrontViewBox; UI_GADGET_USERBOX * RightViewBox; #endif UI_GADGET_ICON * ViewIcon; UI_GADGET_ICON * AllIcon; UI_GADGET_ICON * AxesIcon; UI_GADGET_ICON * ChaseIcon; UI_GADGET_ICON * OutlineIcon; UI_GADGET_ICON * LockIcon; //-NOLIGHTICON- UI_GADGET_ICON * LightIcon; UI_EVENT * DemoBuffer = NULL; //grs_canvas * BigCanvas[2]; //int CurrentBigCanvas = 0; //int BigCanvasFirstTime = 1; int Found_seg_index=0; // Index in Found_segs corresponding to Cursegp void print_status_bar( char message[DIAGNOSTIC_MESSAGE_MAX] ) { int w,h,aw; gr_set_current_canvas( NULL ); gr_set_curfont(editor_font); gr_set_fontcolor( CBLACK, CGREY ); gr_get_string_size( message, &w, &h, &aw ); gr_string( 4, 583, message ); gr_set_fontcolor( CBLACK, CWHITE ); gr_setcolor( CGREY ); gr_rect( 4+w, 583, 799, 599 ); } void print_diagnostic( char message[DIAGNOSTIC_MESSAGE_MAX] ) { int w,h,aw; gr_set_current_canvas( NULL ); gr_set_curfont(editor_font); gr_set_fontcolor( CBLACK, CGREY ); gr_get_string_size( message, &w, &h, &aw ); gr_string( 4, 583, message ); gr_set_fontcolor( CBLACK, CWHITE ); gr_setcolor( CGREY ); gr_rect( 4+w, 583, 799, 599 ); } static char status_line[DIAGNOSTIC_MESSAGE_MAX] = ""; struct tm Editor_status_last_time; void editor_status_fmt( const char *format, ... ) { va_list ap; va_start(ap, format); vsprintf(status_line, format, ap); va_end(ap); Editor_status_last_time = Editor_time_of_day; } void editor_status( const char *text) { strcpy(status_line, text); Editor_status_last_time = Editor_time_of_day; } // int tm_sec; /* seconds after the minute -- [0,61] */ // int tm_min; /* minutes after the hour -- [0,59] */ // int tm_hour; /* hours after midnight -- [0,23] */ // int tm_mday; /* day of the month -- [1,31] */ // int tm_mon; /* months since January -- [0,11] */ // int tm_year; /* years since 1900 */ // int tm_wday; /* days since Sunday -- [0,6] */ // int tm_yday; /* days since January 1 -- [0,365]*/ // int tm_isdst; /* Daylight Savings Time flag */ void clear_editor_status(void) { int cur_time = Editor_time_of_day.tm_hour * 3600 + Editor_time_of_day.tm_min*60 + Editor_time_of_day.tm_sec; int erase_time = Editor_status_last_time.tm_hour * 3600 + Editor_status_last_time.tm_min*60 + Editor_status_last_time.tm_sec + EDITOR_STATUS_MESSAGE_DURATION; if (cur_time > erase_time) { int i; for (i=0; ipos; //@@ Player_init.orient = Player->orient; //@@ Player_init.segnum = Player->segnum; // -- must always save gamesave.sav because the restore-objects code relies on it // -- that code could be made smarter and use the original file, if appropriate. // if (mine_changed) if (gamestate_not_restored == 0) { gamestate_not_restored = 1; save_level("GAMESAVE.LVL"); editor_status("Gamestate saved.\n"); } ai_reset_all_paths(); start_time(); ModeFlag = 3; return 1; } int GotoMainMenu() { ModeFlag = 2; return 1; } #if 0 void ReadLispMacro( FILE * file, char * buffer ) { // char c; // int size=0; // int pcount = 0; // char text[100]; // int i=0; fscanf( file, " { %s } ", buffer ); /* while (1) { c = text[i++]; if (pcount > 0 ) buffer[size++] = c; if ( c == '(' ) pcount++; if ( c == ')' ) break; } buffer[size++] = 0; */ return; } #endif static int (*KeyFunction[2048])(); void medkey_init() { PHYSFS_file * keyfile; char keypress[100]; char line_buffer[200]; int key; int i; //, size; int np; char * LispCommand; MALLOC( LispCommand, char, DIAGNOSTIC_MESSAGE_MAX ); for (i=0; i<2048; i++ ) KeyFunction[i] = NULL; keyfile = PHYSFSX_openReadBuffered( "GLOBAL.KEY" ); if (keyfile) { while (PHYSFSX_fgets(line_buffer, 200, keyfile)) { sscanf(line_buffer, " %s %s ", keypress, LispCommand); //ReadLispMacro( keyfile, LispCommand ); if ( (key=DecodeKeyText( keypress ))!= -1 ) { Assert( key < 2048); KeyFunction[key] = func_get( LispCommand, &np ); } else { Error( "Bad key %s in GLOBAL.KEY!", keypress ); } } PHYSFS_close(keyfile); } d_free( LispCommand ); } static int padnum=0; //@@short camera_objnum; //a camera for viewing. Who knows, might become handy void init_editor_screen(); void gamestate_restore_check(); void init_editor() { void med_show_warning(char *s); // first, make sure we can find the files we need PHYSFSX_addRelToSearchPath("editor/data", 1); // look in source directory first (for work in progress) PHYSFSX_addRelToSearchPath("editor", 1); // then in editor directory PHYSFSX_addRelToSearchPath("editor.zip", 1); // then in a zip file PHYSFSX_addRelToSearchPath("editor.dxa", 1); // or addon pack ui_init(); init_med_functions(); // Must be called before medlisp_init ui_pad_read( 0, "segmove.pad" ); ui_pad_read( 1, "segsize.pad" ); ui_pad_read( 2, "curve.pad" ); ui_pad_read( 3, "texture.pad" ); ui_pad_read( 4, "object.pad" ); ui_pad_read( 5, "objmov.pad" ); ui_pad_read( 6, "group.pad" ); ui_pad_read( 7, "lighting.pad" ); ui_pad_read( 8, "test.pad" ); medkey_init(); game_flush_inputs(); editor_font = gr_init_font( "pc8x16.fnt" ); menubar_init( "MED.MNU" ); Draw_all_segments = 1; // Say draw all segments, not just connected ones if (!Cursegp) Cursegp = &Segments[0]; init_autosave(); // atexit(close_editor); Clear_window = 1; // do full window clear. InitCurve(); restore_effect_bitmap_icons(); if (!set_screen_mode(SCREEN_EDITOR)) { set_screen_mode(SCREEN_MENU); show_menus(); //force back into menu return; } gr_use_palette_table( "palette.256" ); gr_palette_load( gr_palette ); //Editor renders into full (320x200) game screen game_init_render_buffers(320, 200); gr_init_sub_canvas( &_canv_editor, &grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT ); Canv_editor = &_canv_editor; gr_set_current_canvas( Canv_editor ); init_editor_screen(); // load the main editor dialog gr_set_current_canvas( NULL ); gr_set_curfont(editor_font); set_warn_func(med_show_warning); // _MARK_("start of editor");//Nuked to compile -KRB //@@ //create a camera for viewing in the editor. copy position from ConsoleObject //@@ camera_objnum = obj_create(OBJ_CAMERA,0,ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0); //@@ Viewer = &Objects[camera_objnum]; //@@ slew_init(Viewer); //camera is slewing Viewer = ConsoleObject; slew_init(ConsoleObject); init_player_object(); Update_flags = UF_ALL; //set the wire-frame window to be the current view current_view = &LargeView; if (faded_in==0) { faded_in = 1; //gr_pal_fade_in( grd_curscreen->pal ); } gr_set_current_canvas( GameViewBox->canvas ); gr_set_curfont(editor_font); //gr_setcolor( CBLACK ); //gr_deaccent_canvas(); //gr_grey_canvas(); gr_set_curfont(editor_font); FNTScaleX = FNTScaleY = 1; // No font scaling! ui_pad_goto(padnum); ModeFlag = 0; gamestate_restore_check(); } int ShowAbout() { ui_messagebox( -2, -2, 1, "INFERNO Mine Editor\n\n" \ "Copyright (c) 1993 Parallax Software Corp.", "OK"); return 0; } void move_player_2_segment(segment *seg,int side); int SetPlayerFromCurseg() { move_player_2_segment(Cursegp,Curside); Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; return 1; } int fuelcen_create_from_curseg() { Cursegp->special = SEGMENT_IS_FUELCEN; fuelcen_activate(Cursegp, Cursegp->special); return 1; } int repaircen_create_from_curseg() { Int3(); // -- no longer supported! // Cursegp->special = SEGMENT_IS_REPAIRCEN; // fuelcen_activate(Cursegp, Cursegp->special); return 1; } int controlcen_create_from_curseg() { Cursegp->special = SEGMENT_IS_CONTROLCEN; fuelcen_activate(Cursegp, Cursegp->special); return 1; } int robotmaker_create_from_curseg() { Cursegp->special = SEGMENT_IS_ROBOTMAKER; fuelcen_activate(Cursegp, Cursegp->special); return 1; } int fuelcen_reset_all() { fuelcen_reset(); return 1; } int fuelcen_delete_from_curseg() { fuelcen_delete( Cursegp ); return 1; } //@@//this routine places the viewer in the center of the side opposite to curside, //@@//with the view toward the center of curside //@@int SetPlayerFromCursegMinusOne() //@@{ //@@ vms_vector vp; //@@ //@@// int newseg,newside; //@@// get_previous_segment(SEG_PTR_2_NUM(Cursegp),Curside,&newseg,&newside); //@@// move_player_2_segment(&Segments[newseg],newside); //@@ //@@ med_compute_center_point_on_side(&Player->obj_position,Cursegp,Side_opposite[Curside]); //@@ med_compute_center_point_on_side(&vp,Cursegp,Curside); //@@ vm_vec_sub2(&vp,&Player->position); //@@ vm_vector_2_matrix(&Player->orient,&vp,NULL,NULL); //@@ //@@ Player->seg = SEG_PTR_2_NUM(Cursegp); //@@ //@@ Update_flags |= UF_GAME_VIEW_CHANGED; //@@ return 1; //@@} //this constant determines how much of the window will be occupied by the //viewed side when SetPlayerFromCursegMinusOne() is called. It actually //determine how from from the center of the window the farthest point will be #define SIDE_VIEW_FRAC (f1_0*8/10) //80% void move_player_2_segment_and_rotate(segment *seg,int side) { vms_vector vp; vms_vector upvec; static int edgenum=0; compute_segment_center(&ConsoleObject->pos,seg); compute_center_point_on_side(&vp,seg,side); vm_vec_sub2(&vp,&ConsoleObject->pos); vm_vec_sub(&upvec, &Vertices[Cursegp->verts[Side_to_verts[Curside][edgenum%4]]], &Vertices[Cursegp->verts[Side_to_verts[Curside][(edgenum+3)%4]]]); edgenum++; vm_vector_2_matrix(&ConsoleObject->orient,&vp,&upvec,NULL); // vm_vector_2_matrix(&ConsoleObject->orient,&vp,NULL,NULL); obj_relink( ConsoleObject-Objects, SEG_PTR_2_NUM(seg) ); } int SetPlayerFromCursegAndRotate() { move_player_2_segment_and_rotate(Cursegp,Curside); Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; return 1; } //sets the player facing curseg/curside, normal to face0 of curside, and //far enough away to see all of curside int SetPlayerFromCursegMinusOne() { vms_vector view_vec,view_vec2,side_center; vms_vector corner_v[4]; vms_vector upvec; g3s_point corner_p[4]; int i; fix max,view_dist=f1_0*10; static int edgenum=0; int newseg; view_vec = Cursegp->sides[Curside].normals[0]; vm_vec_negate(&view_vec); compute_center_point_on_side(&side_center,Cursegp,Curside); vm_vec_copy_scale(&view_vec2,&view_vec,view_dist); vm_vec_sub(&ConsoleObject->pos,&side_center,&view_vec2); vm_vec_sub(&upvec, &Vertices[Cursegp->verts[Side_to_verts[Curside][edgenum%4]]], &Vertices[Cursegp->verts[Side_to_verts[Curside][(edgenum+3)%4]]]); edgenum++; vm_vector_2_matrix(&ConsoleObject->orient,&view_vec,&upvec,NULL); gr_set_current_canvas(Canv_editor_game); g3_start_frame(); g3_set_view_matrix(&ConsoleObject->pos,&ConsoleObject->orient,Render_zoom); for (i=max=0;i<4;i++) { corner_v[i] = Vertices[Cursegp->verts[Side_to_verts[Curside][i]]]; g3_rotate_point(&corner_p[i],&corner_v[i]); if (labs(corner_p[i].p3_x) > max) max = labs(corner_p[i].p3_x); if (labs(corner_p[i].p3_y) > max) max = labs(corner_p[i].p3_y); } view_dist = fixmul(view_dist,fixdiv(fixdiv(max,SIDE_VIEW_FRAC),corner_p[0].p3_z)); vm_vec_copy_scale(&view_vec2,&view_vec,view_dist); vm_vec_sub(&ConsoleObject->pos,&side_center,&view_vec2); //obj_relink(ConsoleObject-Objects, SEG_PTR_2_NUM(Cursegp) ); //update_object_seg(ConsoleObject); //might have backed right out of curseg newseg = find_point_seg(&ConsoleObject->pos,SEG_PTR_2_NUM(Cursegp) ); if (newseg != -1) obj_relink(ConsoleObject-Objects,newseg); Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED; return 1; } int ToggleLighting(void) { Lighting_on++; if (Lighting_on >= 2) Lighting_on = 0; Update_flags |= UF_GAME_VIEW_CHANGED; switch (Lighting_on) { case 0: diagnostic_message("Lighting off."); break; case 1: diagnostic_message("Static lighting."); break; case 2: diagnostic_message("Ship lighting."); break; case 3: diagnostic_message("Ship and static lighting."); break; } return Lighting_on; } void find_concave_segs(); int FindConcaveSegs() { find_concave_segs(); Update_flags |= UF_ED_STATE_CHANGED; //list may have changed return 1; } int DosShell() { int ok, w, h; grs_bitmap * save_bitmap; ok = 1; // Save the current graphics state. w = grd_curscreen->sc_canvas.cv_bitmap.bm_w; h = grd_curscreen->sc_canvas.cv_bitmap.bm_h; save_bitmap = gr_create_bitmap( w, h ); gr_bm_ubitblt(w, h, 0, 0, 0, 0, &(grd_curscreen->sc_canvas.cv_bitmap), save_bitmap ); // gr_set_mode( SM_ORIGINAL ); fflush(stdout); key_close(); #ifdef __MSDOS__ ok = spawnl(P_WAIT,getenv("COMSPEC"), NULL ); #endif key_init(); gr_set_mode(grd_curscreen->sc_mode); gr_bm_ubitblt(w, h, 0, 0, 0, 0, save_bitmap, &(grd_curscreen->sc_canvas.cv_bitmap)); gr_free_bitmap( save_bitmap ); //gr_pal_setblock( 0, 256, grd_curscreen->pal ); //gr_use_palette_table(); return ok; } int ToggleOutlineMode() { #ifndef NDEBUG int mode; mode=toggle_outline_mode(); if (mode) { //if (keypress != KEY_O) diagnostic_message("[Ctrl-O] Outline Mode ON."); //else // diagnostic_message("Outline Mode ON."); } else { //if (keypress != KEY_O) diagnostic_message("[Ctrl-O] Outline Mode OFF."); //else // diagnostic_message("Outline Mode OFF."); } Update_flags |= UF_GAME_VIEW_CHANGED; return mode; #else return 1; #endif } //@@int do_reset_orient() //@@{ //@@ slew_reset_orient(SlewObj); //@@ //@@ Update_flags |= UF_GAME_VIEW_CHANGED; //@@ //@@ * (ubyte *) 0x417 &= ~0x20; //@@ //@@ return 1; //@@} int GameZoomOut() { Render_zoom = fixmul(Render_zoom,68985); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } int GameZoomIn() { Render_zoom = fixmul(Render_zoom,62259); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } int med_keypad_goto_0() { ui_pad_goto(0); return 0; } int med_keypad_goto_1() { ui_pad_goto(1); return 0; } int med_keypad_goto_2() { ui_pad_goto(2); return 0; } int med_keypad_goto_3() { ui_pad_goto(3); return 0; } int med_keypad_goto_4() { ui_pad_goto(4); return 0; } int med_keypad_goto_5() { ui_pad_goto(5); return 0; } int med_keypad_goto_6() { ui_pad_goto(6); return 0; } int med_keypad_goto_7() { ui_pad_goto(7); return 0; } int med_keypad_goto_8() { ui_pad_goto(8); return 0; } #define PAD_WIDTH 30 #define PAD_WIDTH1 (PAD_WIDTH + 7) int editor_screen_open = 0; int editor_handler(UI_DIALOG *dlg, d_event *event, void *data); //setup the editors windows, canvases, gadgets, etc. void init_editor_screen() { // grs_bitmap * bmp; if (editor_screen_open) return; grd_curscreen->sc_canvas.cv_font = editor_font; //create canvas for game on the editor screen initializing = 1; gr_set_current_canvas(Canv_editor); Canv_editor->cv_font = editor_font; gr_init_sub_canvas(Canv_editor_game,Canv_editor,GAMEVIEW_X,GAMEVIEW_Y,GAMEVIEW_W,GAMEVIEW_H); //Editor renders into full (320x200) game screen init_info = 1; //do other editor screen setup // Since the palette might have changed, find some good colors... CBLACK = gr_find_closest_color( 1, 1, 1 ); CGREY = gr_find_closest_color( 28, 28, 28 ); CWHITE = gr_find_closest_color( 38, 38, 38 ); CBRIGHT = gr_find_closest_color( 60, 60, 60 ); CRED = gr_find_closest_color( 63, 0, 0 ); gr_set_curfont(editor_font); gr_set_fontcolor( CBLACK, CWHITE ); EditorWindow = ui_create_dialog( 0 , 0, ED_SCREEN_W, ED_SCREEN_H, DF_FILLED, editor_handler, NULL ); LargeViewBox = ui_add_gadget_userbox( EditorWindow,LVIEW_X,LVIEW_Y,LVIEW_W,LVIEW_H); #if ORTHO_VIEWS TopViewBox = ui_add_gadget_userbox( EditorWindow,TVIEW_X,TVIEW_Y,TVIEW_W,TVIEW_H); FrontViewBox = ui_add_gadget_userbox( EditorWindow,FVIEW_X,FVIEW_Y,FVIEW_W,FVIEW_H); RightViewBox = ui_add_gadget_userbox( EditorWindow,RVIEW_X,RVIEW_Y,RVIEW_W,RVIEW_H); #endif ui_gadget_calc_keys(EditorWindow); //make tab work for all windows GameViewBox = ui_add_gadget_userbox( EditorWindow, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H ); // GroupViewBox = ui_add_gadget_userbox( EditorWindow,GVIEW_X,GVIEW_Y,GVIEW_W,GVIEW_H); // GameViewBox->when_tab = GameViewBox->when_btab = (UI_GADGET *) LargeViewBox; // LargeViewBox->when_tab = LargeViewBox->when_btab = (UI_GADGET *) GameViewBox; // ui_gadget_calc_keys(EditorWindow); //make tab work for all windows ViewIcon = ui_add_gadget_icon( EditorWindow, "Lock\nview", 455,25+530, 40, 22, KEY_V+KEY_CTRLED, ToggleLockViewToCursegp ); AllIcon = ui_add_gadget_icon( EditorWindow, "Draw\nall", 500,25+530, 40, 22, -1, ToggleDrawAllSegments ); AxesIcon = ui_add_gadget_icon( EditorWindow, "Coord\naxes",545,25+530, 40, 22, KEY_D+KEY_CTRLED, ToggleCoordAxes ); //-NOLIGHTICON- LightIcon = ui_add_gadget_icon( EditorWindow, "Light\ning", 590,25+530, 40, 22, KEY_L+KEY_SHIFTED,ToggleLighting ); ChaseIcon = ui_add_gadget_icon( EditorWindow, "Chase\nmode",635,25+530, 40, 22, -1, ToggleChaseMode ); OutlineIcon = ui_add_gadget_icon( EditorWindow, "Out\nline", 680,25+530, 40, 22, KEY_O+KEY_CTRLED, ToggleOutlineMode ); LockIcon = ui_add_gadget_icon( EditorWindow, "Lock\nstep", 725,25+530, 40, 22, KEY_L+KEY_CTRLED, ToggleLockstep ); meddraw_init_views(LargeViewBox->canvas); //ui_add_gadget_button( EditorWindow, 460, 510, 50, 25, "Quit", ExitEditor ); //ui_add_gadget_button( EditorWindow, 520, 510, 50, 25, "Lisp", CallLisp ); //ui_add_gadget_button( EditorWindow, 580, 510, 50, 25, "Mine", MineMenu ); //ui_add_gadget_button( EditorWindow, 640, 510, 50, 25, "Help", DoHelp ); //ui_add_gadget_button( EditorWindow, 460, 540, 50, 25, "Macro", MacroMenu ); //ui_add_gadget_button( EditorWindow, 520, 540, 50, 25, "About", ShowAbout ); //ui_add_gadget_button( EditorWindow, 640, 540, 50, 25, "Shell", DosShell ); ui_pad_activate( EditorWindow, PAD_X, PAD_Y ); Pad_info = info_window_create(); ui_add_gadget_button( EditorWindow, PAD_X+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "<<", med_keypad_goto_prev ); ui_add_gadget_button( EditorWindow, PAD_X+PAD_WIDTH1+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, ">>", med_keypad_goto_next ); { int i; i = 0; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SR", med_keypad_goto_0 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SS", med_keypad_goto_1 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "CF", med_keypad_goto_2 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TM", med_keypad_goto_3 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OP", med_keypad_goto_4 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OR", med_keypad_goto_5 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "GE", med_keypad_goto_6 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "LI", med_keypad_goto_7 ); i++; ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TT", med_keypad_goto_8 ); } gr_set_curfont(editor_font); menubar_show(); // INIT TEXTURE STUFF texpage_init( EditorWindow ); objpage_init( EditorWindow ); EditorWindow->keyboard_focus_gadget = (UI_GADGET *)LargeViewBox; // BigCanvas[0]->cv_font = grd_curscreen->sc_canvas.cv_font; // BigCanvas[1]->cv_font = grd_curscreen->sc_canvas.cv_font; // BigCanvasFirstTime = 1; Update_flags = UF_ALL; initializing = 0; editor_screen_open = 1; } //shutdown ui on the editor screen void close_editor_screen() { if (!editor_screen_open) return; editor_screen_open = 0; ui_pad_deactivate(); if (Pad_info) window_close(Pad_info); //ui_close_dialog(EditorWindow); // moved into handler, so we can handle the quit request //EditorWindow = NULL; close_all_windows(); // CLOSE TEXTURE STUFF texpage_close(); objpage_close(); menubar_hide(); } void med_show_warning(char *s) { grs_canvas *save_canv=grd_curcanv; //gr_pal_fade_in(grd_curscreen->pal); //in case palette is blacked ui_messagebox(-2,-2,1,s,"OK"); gr_set_current_canvas(save_canv); } // Returns 1 if OK to trash current mine. int SafetyCheck() { int x; if (mine_changed) { x = nm_messagebox( "Warning!", 2, "Cancel", "OK", "You are about to lose work." ); if (x<1) { return 0; } } return 1; } //called at the end of the program void close_editor() { // _MARK_("end of editor");//Nuked to compile -KRB #ifndef __LINUX__ set_warn_func(msgbox_warning); #else clear_warn_func(NULL); #endif close_editor_screen(); //kill our camera object Viewer = ConsoleObject; //reset viewer //@@obj_delete(camera_objnum); padnum = ui_pad_get_current(); close_autosave(); ui_close(); gr_close_font(editor_font); PHYSFSX_removeRelFromSearchPath("editor/data"); PHYSFSX_removeRelFromSearchPath("editor"); PHYSFSX_removeRelFromSearchPath("editor.zip"); PHYSFSX_removeRelFromSearchPath("editor.dxa"); switch (ModeFlag) { case 1: if (Game_wind) window_close(Game_wind); break; case 2: if (Game_wind) window_close(Game_wind); set_screen_mode(SCREEN_MENU); //put up menu screen show_menus(); break; case 3: set_screen_mode(SCREEN_GAME); //put up game screen Game_mode = GM_EDITOR; editor_reset_stuff_on_level(); N_players = 1; break; } return; } //variables for find segments process // --------------------------------------------------------------------------------------------------- // Subtract all elements in Found_segs from selected list. void subtract_found_segments_from_selected_list(void) { int s,f; for (f=0; fpos; Save_position.orient = ConsoleObject->orient; Save_position.segnum = ConsoleObject->segnum; load_level("GAMESAVE.LVL"); // Restore current position if (Save_position.segnum <= Highest_segment_index) { ConsoleObject->pos = Save_position.pos; ConsoleObject->orient = Save_position.orient; obj_relink(ConsoleObject-Objects,Save_position.segnum); } gamestate_not_restored = 0; Update_flags |= UF_WORLD_CHANGED; } else gamestate_not_restored = 1; } } int RestoreGameState() { load_level("GAMESAVE.LVL"); gamestate_not_restored = 0; editor_status("Gamestate restored.\n"); Update_flags |= UF_WORLD_CHANGED; return 0; } extern void check_wall_validity(void); // Handler for the main editor dialog int editor_handler(UI_DIALOG *dlg, d_event *event, void *data) { editor_view *new_cv; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); else if (event->type == EVENT_WINDOW_CLOSE) { close_editor(); EditorWindow = NULL; return 0; } // Update the windows if (event->type == EVENT_UI_DIALOG_DRAW) { gr_set_curfont(editor_font); // Draw status box gr_set_current_canvas( NULL ); gr_setcolor( CGREY ); gr_rect(STATUS_X,STATUS_Y,STATUS_X+STATUS_W-1,STATUS_Y+STATUS_H-1); //0, 582, 799, 599 ); medlisp_update_screen(); calc_frame_time(); texpage_do(event); objpage_do(event); ui_pad_draw(EditorWindow, PAD_X, PAD_Y); print_status_bar(status_line); TimedAutosave(mine_filename); // shows the time, hence here set_editor_time_of_day(); return 1; } if ((selected_gadget == (UI_GADGET *)GameViewBox && !render_3d_in_big_window) || (selected_gadget == (UI_GADGET *)LargeViewBox && render_3d_in_big_window)) switch (event->type) { case EVENT_MOUSE_BUTTON_UP: case EVENT_MOUSE_BUTTON_DOWN: break; case EVENT_MOUSE_MOVED: if (!keyd_pressed[ KEY_LCTRL ] && !keyd_pressed[ KEY_RCTRL ]) break; case EVENT_JOYSTICK_BUTTON_UP: case EVENT_JOYSTICK_BUTTON_DOWN: case EVENT_JOYSTICK_MOVED: case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: case EVENT_IDLE: kconfig_read_controls(event, 1); if (slew_frame(0)) { //do movement and check keys Update_flags |= UF_GAME_VIEW_CHANGED; if (Gameview_lockstep) { Cursegp = &Segments[ConsoleObject->segnum]; med_create_new_segment_from_cursegp(); Update_flags |= UF_ED_STATE_CHANGED; } rval = 1; } break; default: break; } //do non-essential stuff in idle event if (event->type == EVENT_IDLE) { check_wall_validity(); Assert(Num_walls>=0); if (Gameview_lockstep) { static segment *old_cursegp=NULL; static int old_curside=-1; if (old_cursegp!=Cursegp || old_curside!=Curside) { SetPlayerFromCursegMinusOne(); old_cursegp = Cursegp; old_curside = Curside; } } if ( event_get_idle_seconds() > COMPRESS_INTERVAL ) { med_compress_mine(); event_reset_idle_seconds(); } // Commented out because it occupies about 25% of time in twirling the mine. // Removes some Asserts.... // med_check_all_vertices(); clear_editor_status(); // if enough time elapsed, clear editor status message } gr_set_current_canvas( GameViewBox->canvas ); // Remove keys used for slew switch(keypress) { case KEY_PAD9: case KEY_PAD7: case KEY_PADPLUS: case KEY_PADMINUS: case KEY_PAD8: case KEY_PAD2: case KEY_LBRACKET: case KEY_RBRACKET: case KEY_PAD1: case KEY_PAD3: case KEY_PAD6: case KEY_PAD4: keypress = 0; } if ((keypress&0xff)==KEY_LSHIFT) keypress=0; if ((keypress&0xff)==KEY_RSHIFT) keypress=0; if ((keypress&0xff)==KEY_LCTRL) keypress=0; if ((keypress&0xff)==KEY_RCTRL) keypress=0; // if ((keypress&0xff)==KEY_LALT) keypress=0; // if ((keypress&0xff)==KEY_RALT) keypress=0; //=================== DO FUNCTIONS ==================== if ( KeyFunction[ keypress ] != NULL ) { KeyFunction[keypress](); keypress = 0; rval = 1; } switch (keypress) { case 0: case KEY_Z: case KEY_G: case KEY_LALT: case KEY_RALT: case KEY_LCTRL: case KEY_RCTRL: case KEY_LSHIFT: case KEY_RSHIFT: case KEY_LAPOSTRO: break; case KEY_SHIFTED + KEY_L: ToggleLighting(); rval = 1; break; case KEY_F1: render_3d_in_big_window = !render_3d_in_big_window; Update_flags |= UF_ALL; rval = 1; break; default: if (!rval) { char kdesc[100]; GetKeyDescription( kdesc, keypress ); editor_status_fmt("Error: %s isn't bound to anything.", kdesc ); } } //================================================================ if (ModeFlag) { ui_close_dialog(EditorWindow); return 0; } // if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)GameViewBox) current_view=NULL; // if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)GroupViewBox) current_view=NULL; new_cv = current_view; #if ORTHO_VIEWS if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)LargeViewBox) new_cv=&LargeView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)TopViewBox) new_cv=&TopView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)FrontViewBox) new_cv=&FrontView; if (EditorWindow->keyboard_focus_gadget == (UI_GADGET *)RightViewBox) new_cv=&RightView; #endif if (new_cv != current_view ) { current_view->ev_changed = 1; new_cv->ev_changed = 1; current_view = new_cv; } // DO TEXTURE STUFF if (texpage_do(event)) rval = 1; if (objpage_do(event)) rval = 1; // Process selection of Cursegp using mouse. if (GADGET_PRESSED(LargeViewBox) && !render_3d_in_big_window) { int xcrd,ycrd; xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; find_segments(xcrd,ycrd,LargeViewBox->canvas,&LargeView,Cursegp,Big_depth); // Sets globals N_found_segs, Found_segs // If shift is down, then add segment to found list if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ]) subtract_found_segments_from_selected_list(); else add_found_segments_to_selected_list(); Found_seg_index = 0; if (N_found_segs > 0) { sort_seg_list(N_found_segs,Found_segs,&ConsoleObject->pos); Cursegp = &Segments[Found_segs[0]]; med_create_new_segment_from_cursegp(); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); } Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED; } if ((event->type == EVENT_UI_USERBOX_DRAGGED) && (ui_event_get_gadget(event) == (UI_GADGET *)GameViewBox)) { int x, y; x = GameViewBox->b1_drag_x2; y = GameViewBox->b1_drag_y2; gr_set_current_canvas( GameViewBox->canvas ); gr_setcolor( 15 ); gr_rect( x-1, y-1, x+1, y+1 ); } // Set current segment and side by clicking on a polygon in game window. // If ctrl pressed, also assign current texture map to that side. //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) { if ((GADGET_PRESSED(GameViewBox) && !render_3d_in_big_window) || (GADGET_PRESSED(LargeViewBox) && render_3d_in_big_window)) { int xcrd,ycrd; int seg,side,face,poly,tmap; if (render_3d_in_big_window) { xcrd = LargeViewBox->b1_drag_x1; ycrd = LargeViewBox->b1_drag_y1; } else { xcrd = GameViewBox->b1_drag_x1; ycrd = GameViewBox->b1_drag_y1; } //Int3(); if (find_seg_side_face(xcrd,ycrd,&seg,&side,&face,&poly)) { if (seg<0) { //found an object Cur_object_index = -seg-1; editor_status_fmt("Object %d selected.",Cur_object_index); Update_flags |= UF_ED_STATE_CHANGED; } else { // See if either shift key is down and, if so, assign texture map if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) { Cursegp = &Segments[seg]; Curside = side; AssignTexture(); med_create_new_segment_from_cursegp(); editor_status("Texture assigned"); } else if (keyd_pressed[KEY_G]) { tmap = Segments[seg].sides[side].tmap_num; texpage_grab_current(tmap); editor_status( "Texture grabbed." ); } else if (keyd_pressed[ KEY_LAPOSTRO] ) { move_object_to_mouse_click(); } else { Cursegp = &Segments[seg]; Curside = side; med_create_new_segment_from_cursegp(); editor_status("Curseg and curside selected"); } } Update_flags |= UF_ED_STATE_CHANGED; } else editor_status("Click on non-texture ingored"); } // Allow specification of LargeView using mouse if (event->type == EVENT_MOUSE_MOVED && (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ])) { int dx, dy, dz; event_mouse_get_delta(event, &dx, &dy, &dz); if ((dx != 0) && (dy != 0)) { vms_matrix MouseRotMat,tempm; GetMouseRotation( dx, dy, &MouseRotMat ); vm_matrix_x_matrix(&tempm,&LargeView.ev_matrix,&MouseRotMat); LargeView.ev_matrix = tempm; LargeView.ev_changed = 1; Large_view_index = -1; // say not one of the orthogonal views rval = 1; } } if (event->type == EVENT_MOUSE_MOVED) { int dx, dy, dz; event_mouse_get_delta(event, &dx, &dy, &dz); if (dz != 0) { current_view->ev_dist += dz*10000; current_view->ev_changed = 1; } } return rval; } void test_fade(void) { int i,c; for (c=0; c<256; c++) { con_printf(CON_DEBUG,"%4i: {%3i %3i %3i} ",c,gr_palette[3*c],gr_palette[3*c+1],gr_palette[3*c+2]); for (i=0; i<16; i++) { int col = gr_fade_table[256*i+c]; con_printf(CON_DEBUG,"[%3i %3i %3i] ",gr_palette[3*col],gr_palette[3*col+1],gr_palette[3*col+2]); } if ( (c%16) == 15) con_printf(CON_DEBUG,"\n"); con_printf(CON_DEBUG,"\n"); } } void dump_stuff(void) { int i,j,prev_color; con_printf(CON_DEBUG,"Palette:\n"); for (i=0; i<256; i++) con_printf(CON_DEBUG,"%3i: %2i %2i %2i\n",i,gr_palette[3*i],gr_palette[3*i+1],gr_palette[3*i+2]); for (i=0; i<16; i++) { con_printf(CON_DEBUG,"\nFade table #%i\n",i); for (j=0; j<256; j++) { int c = gr_fade_table[i*256 + j]; con_printf(CON_DEBUG,"[%3i %2i %2i %2i] ",c, gr_palette[3*c], gr_palette[3*c+1], gr_palette[3*c+2]); if ((j % 8) == 7) con_printf(CON_DEBUG,"\n"); } } con_printf(CON_DEBUG,"Colors indexed by intensity:\n"); con_printf(CON_DEBUG,". = change from previous, * = no change\n"); for (j=0; j<256; j++) { con_printf(CON_DEBUG,"%3i: ",j); prev_color = -1; for (i=0; i<16; i++) { int c = gr_fade_table[i*256 + j]; if (c == prev_color) con_printf(CON_DEBUG,"*"); else con_printf(CON_DEBUG,"."); prev_color = c; } con_printf(CON_DEBUG," "); for (i=0; i<16; i++) { int c = gr_fade_table[i*256 + j]; con_printf(CON_DEBUG,"[%3i %2i %2i %2i] ", c, gr_palette[3*c], gr_palette[3*c+1], gr_palette[3*c+2]); } con_printf(CON_DEBUG,"\n"); } } #ifndef NDEBUG int MarkStart(void) { char mystr[30]; sprintf(mystr,"mark %i start",Mark_count); // _MARK_(mystr);//Nuked to compile -KRB return 1; } int MarkEnd(void) { char mystr[30]; sprintf(mystr,"mark %i end",Mark_count); Mark_count++; // _MARK_(mystr);//Nuked to compile -KRB return 1; } #endif dxx-rebirth-0.58.1-d1x/editor/meddraw.c000066400000000000000000000575451217717257200176470ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Med drawing functions. * */ #include #include #include #include #include "inferno.h" #include "segment.h" #include "segpoint.h" #include "gameseg.h" #include "gr.h" #include "ui.h" #include "editor/editor.h" #include "editor/esegment.h" #include "wall.h" #include "switch.h" #include "key.h" #include "mouse.h" #include "dxxerror.h" #include "medlisp.h" #include "u_mem.h" #include "render.h" #include "game.h" #include "kdefs.h" #include "func.h" #include "textures.h" #include "screens.h" #include "texmap.h" #include "object.h" #include "fuelcen.h" // Colors used in editor for indicating various kinds of segments. #define SELECT_COLOR BM_XRGB( 63/2 , 41/2 , 0/2) #define FOUND_COLOR BM_XRGB( 0/2 , 30/2 , 45/2) #define WARNING_COLOR BM_XRGB( 63/2 , 0/2 , 0/2) #define AXIS_COLOR BM_XRGB( 63/2 , 0/2 , 63/2) #define PLAINSEG_COLOR BM_XRGB( 45/2 , 45/2 , 45/2) #define MARKEDSEG_COLOR BM_XRGB( 0/2 , 63/2 , 0/2) #define MARKEDSIDE_COLOR BM_XRGB( 0/2 , 63/2 , 63/2) #define CURSEG_COLOR BM_XRGB( 63/2 , 63/2 , 63/2) #define CURSIDE_COLOR BM_XRGB( 63/2 , 63/2 , 0/2) #define CUREDGE_COLOR BM_XRGB( 0 , 63/2 , 0 ) #define GROUPSEG_COLOR BM_XRGB( 0/2 , 0/2 , 63/2) #define GROUPSIDE_COLOR BM_XRGB( 63/2 , 0/2 , 45/2) #define GROUP_COLOR BM_XRGB( 0/2 , 45/2 , 0/2) #define ROBOT_COLOR BM_XRGB( 31 , 0 , 0 ) #define PLAYER_COLOR BM_XRGB( 0 , 0 , 31 ) int Search_mode=0; //if true, searching for segments at given x,y int Search_x,Search_y; int Automap_test=0; // Set to 1 to show wireframe in automap mode. void draw_seg_objects(segment *seg) { int objnum; for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next) { object *obj = &Objects[objnum]; g3s_point sphere_point; if ((obj->type==OBJ_PLAYER) && (objnum > 0 )) gr_setcolor(BM_XRGB( 0, 25, 0 )); else gr_setcolor(obj==ConsoleObject?PLAYER_COLOR:ROBOT_COLOR); g3_rotate_point(&sphere_point,&obj->pos); g3_draw_sphere(&sphere_point,obj->size); } } void draw_line(int pnum0,int pnum1) { g3_draw_line(&Segment_points[pnum0],&Segment_points[pnum1]); } // ---------------------------------------------------------------------------- void draw_segment(segment *seg) { int *svp; int nv; g3s_codes cc; if (seg->segnum == -1) //this segment doesn't exitst return; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? int i; for (i=0;i<4;i++) draw_line(svp[i],svp[i+4]); for (i=0;i<3;i++) { draw_line(svp[i] ,svp[i+1]); draw_line(svp[i+4],svp[i+4+1]); } draw_line(svp[0],svp[3]); draw_line(svp[0+4],svp[3+4]); } } //for looking for segment under a mouse click void check_segment(segment *seg) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? int fn; gr_setcolor(0); #ifdef OGL g3_end_frame(); #endif gr_pixel(Search_x,Search_y); //set our search pixel to color zero #ifdef OGL g3_start_frame(); #endif gr_setcolor(1); //and render in color one for (fn=0;fn<6;fn++) { g3s_point *vert_list[4]; vert_list[0] = &Segment_points[seg->verts[Side_to_verts[fn][0]]]; vert_list[1] = &Segment_points[seg->verts[Side_to_verts[fn][1]]]; vert_list[2] = &Segment_points[seg->verts[Side_to_verts[fn][2]]]; g3_check_and_draw_poly(3,vert_list,NULL,NULL); vert_list[1] = &Segment_points[seg->verts[Side_to_verts[fn][2]]]; vert_list[2] = &Segment_points[seg->verts[Side_to_verts[fn][3]]]; g3_check_and_draw_poly(3,vert_list,NULL,NULL); } if (gr_ugpixel(&grd_curcanv->cv_bitmap,Search_x,Search_y) == 1) { if (N_found_segs < MAX_FOUND_SEGS) Found_segs[N_found_segs++] = SEG_PTR_2_NUM(seg); else Warning("Found too many segs! (limit=%d)",MAX_FOUND_SEGS); } } } // ---------------------------------------------------------------------------- void draw_seg_side(segment *seg,int side) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? int i; for (i=0;i<3;i++) draw_line(svp[Side_to_verts[side][i]],svp[Side_to_verts[side][i+1]]); draw_line(svp[Side_to_verts[side][i]],svp[Side_to_verts[side][0]]); } } void draw_side_edge(segment *seg,int side,int edge) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) //on screen? draw_line(svp[Side_to_verts[side][edge]],svp[Side_to_verts[side][(edge+1)%4]]); } int Show_triangulations=0; //edge types - lower number types have precedence #define ET_FACING 0 //this edge on a facing face #define ET_NOTFACING 1 //this edge on a non-facing face #define ET_NOTUSED 2 //no face uses this edge #define ET_NOTEXTANT 3 //would exist if side were triangulated #define ET_EMPTY 255 //this entry in array is empty //colors for those types //int edge_colors[] = {BM_RGB(45/2,45/2,45/2), // BM_RGB(45/3,45/3,45/3), //BM_RGB(0,0,45), // // BM_RGB(45/4,45/4,45/4)}; //BM_RGB(0,45,0)}; // int edge_colors[] = { 54, 59, 64 }; typedef struct seg_edge { union { struct {int v0,v1;} __pack__ n; long vv; }v; ushort type; ubyte face_count, backface_count; } seg_edge; #define MAX_EDGES (MAX_VERTICES*4) seg_edge edge_list[MAX_EDGES]; int used_list[MAX_EDGES]; //which entries in edge_list have been used int n_used; int edge_list_size; //set each frame #define HASH(a,b) ((a*5+b) % edge_list_size) //define edge numberings int edges[] = { 0*8+1, // edge 0 0*8+3, // edge 1 0*8+4, // edge 2 1*8+2, // edge 3 1*8+5, // edge 4 2*8+3, // edge 5 2*8+6, // edge 6 3*8+7, // edge 7 4*8+5, // edge 8 4*8+7, // edge 9 5*8+6, // edge 10 6*8+7, // edge 11 0*8+5, // right cross 0*8+7, // top cross 1*8+3, // front cross 2*8+5, // bottom cross 2*8+7, // left cross 4*8+6, // back cross //crosses going the other way 1*8+4, // other right cross 3*8+4, // other top cross 0*8+2, // other front cross 1*8+6, // other bottom cross 3*8+6, // other left cross 5*8+7, // other back cross }; #define N_NORMAL_EDGES 12 //the normal edges of a box #define N_EXTRA_EDGES 12 //ones created by triangulation #define N_EDGES_PER_SEGMENT (N_NORMAL_EDGES+N_EXTRA_EDGES) #define swap(a,b) do {int t; t=(a); (a)=(b); (b)=t;} while (0) //given two vertex numbers on a segment (range 0..7), tell what edge number it is int find_edge_num(int v0,int v1) { int i; int vv; int *edgep = edges; if (v0 > v1) swap(v0,v1); vv = v0*8+v1; // for (i=0;i v1) swap(v0,v1); found = find_edge(v0,v1,&e); if (found == -1) { e->v.n.v0 = v0; e->v.n.v1 = v1; e->type = type; used_list[n_used] = e-edge_list; if (type == ET_FACING) edge_list[used_list[n_used]].face_count++; else if (type == ET_NOTFACING) edge_list[used_list[n_used]].backface_count++; n_used++; } else { if (type < e->type) e->type = type; if (type == ET_FACING) edge_list[found].face_count++; else if (type == ET_NOTFACING) edge_list[found].backface_count++; } } //adds a segment's edges to the edge list void add_edges(segment *seg) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? int i,sn,fn,vn; int flag; ubyte edge_flags[N_EDGES_PER_SEGMENT]; for (i=0;isides[sn]; int num_faces, num_vertices; int vertex_list[6]; create_all_vertex_lists(&num_faces, vertex_list, seg-Segments, sn); if (num_faces == 1) num_vertices = 4; else num_vertices = 3; for (fn=0; fnverts[vertex_list[fn*3]]],&sidep->normals[fn])) flag = ET_NOTFACING; else flag = ET_FACING; v0 = &vertex_list[fn*3]; for (vn=0; vnverts[edges[i]/8],seg->verts[edges[i]&7],edge_flags[i]); } } // ---------------------------------------------------------------------------- void draw_trigger_side(segment *seg,int side) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? // Draw diagonals draw_line(svp[Side_to_verts[side][0]],svp[Side_to_verts[side][2]]); //g3_draw_line(svp[Side_to_verts[side][1]],svp[Side_to_verts[side][3]]); } } // ---------------------------------------------------------------------------- void draw_wall_side(segment *seg,int side) { int *svp; int nv; g3s_codes cc; med_get_vertex_list(seg,&nv,&svp); // set nv = number of vertices, svp = pointer to vertex indices cc=rotate_list(nv,svp); if (! cc.uand) { //all off screen? // Draw diagonals draw_line(svp[Side_to_verts[side][0]],svp[Side_to_verts[side][2]]); draw_line(svp[Side_to_verts[side][1]],svp[Side_to_verts[side][3]]); } } #define WALL_BLASTABLE_COLOR BM_XRGB( 31/2 , 0/2 , 0/2) // RED #define WALL_DOOR_COLOR BM_XRGB( 0/2 , 0/2 , 31/2) // DARK BLUE #define WALL_DOOR_LOCKED_COLOR BM_XRGB( 0/2 , 0/2 , 63/2) // BLUE #define WALL_AUTO_DOOR_COLOR BM_XRGB( 0/2 , 31/2 , 0/2) // DARK GREEN #define WALL_AUTO_DOOR_LOCKED_COLOR BM_XRGB( 0/2 , 63/2 , 0/2) // GREEN #define WALL_ILLUSION_COLOR BM_XRGB( 63/2 , 0/2 , 63/2) // PURPLE #define TRIGGER_COLOR BM_XRGB( 63/2 , 63/2 , 0/2) // YELLOW #define TRIGGER_DAMAGE_COLOR BM_XRGB( 63/2 , 63/2 , 0/2) // YELLOW // ---------------------------------------------------------------------------------------------------------------- // Draws special walls (for now these are just removable walls.) void draw_special_wall( segment *seg, int side ) { gr_setcolor(PLAINSEG_COLOR); if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE) gr_setcolor(WALL_BLASTABLE_COLOR); if (Walls[seg->sides[side].wall_num].type == WALL_DOOR) gr_setcolor(WALL_DOOR_COLOR); if (Walls[seg->sides[side].wall_num].type == WALL_ILLUSION) gr_setcolor(GROUPSIDE_COLOR); if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_LOCKED) gr_setcolor(WALL_DOOR_LOCKED_COLOR); if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO) gr_setcolor(WALL_AUTO_DOOR_COLOR); if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_LOCKED) if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO) gr_setcolor(WALL_AUTO_DOOR_LOCKED_COLOR); if (Walls[seg->sides[side].wall_num].type == WALL_OPEN) gr_setcolor(PLAINSEG_COLOR); draw_wall_side(seg,side); if (Walls[seg->sides[side].wall_num].trigger != -1) { gr_setcolor(TRIGGER_COLOR); draw_trigger_side(seg,side); } gr_setcolor(PLAINSEG_COLOR); } // ---------------------------------------------------------------------------------------------------------------- // Recursively parse mine structure, drawing segments. void draw_mine_sub(int segnum,int depth) { segment *mine_ptr; if (Been_visited[segnum]) return; // If segment already drawn, return. Been_visited[segnum] = 1; // Say that this segment has been drawn. mine_ptr = &Segments[segnum]; // If this segment is active, process it, else skip it. if (mine_ptr->segnum != -1) { int side; if (Search_mode) check_segment(mine_ptr); else add_edges(mine_ptr); //add this segments edges to list if (depth != 0) { for (side=0; sidechildren[side])) { if (mine_ptr->sides[side].wall_num != -1) draw_special_wall(mine_ptr, side); draw_mine_sub(mine_ptr->children[side],depth-1); } } } } } void draw_mine_edges(int automap_flag) { int i,type; seg_edge *e; for (type=ET_NOTUSED;type>=ET_FACING;type--) { gr_setcolor(edge_colors[type]); for (i=0;itype == type) if ((!automap_flag) || (e->face_count == 1)) draw_line(e->v.n.v0,e->v.n.v1); } } } //draws an entire mine void draw_mine(segment *mine_ptr,int depth) { int i; // clear visited list for (i=0; i<=Highest_segment_index; i++) Been_visited[i] = 0; edge_list_size = min(Num_segments*12,MAX_EDGES); //make maybe smaller than max // clear edge list for (i=0; i -1) { gr_setcolor(GROUP_COLOR); for (s=0; sev_matrix.fvec; vm_vec_scale(&viewer_position,-v->ev_dist); vm_vec_add2(&viewer_position,&Ed_view_target); gr_clear_canvas(0); g3_start_frame(); g3_set_view_matrix(&viewer_position,&v->ev_matrix,v->ev_zoom); render_start_frame(); gr_setcolor(PLAINSEG_COLOR); // Draw all segments or only connected segments. // We might want to draw all segments if we have broken the mine into pieces. if (Draw_all_segments) draw_mine_all(Segments, Automap_test); else draw_mine(mine_ptr,depth); // Draw the found segments if (!Automap_test) { draw_warning_segments(); draw_group_segments(); draw_found_segments(); draw_selected_segments(); draw_special_segments(); // Highlight group segment and side. if (current_group > -1) if (Groupsegp[current_group]) { gr_setcolor(GROUPSEG_COLOR); draw_segment(Groupsegp[current_group]); gr_setcolor(GROUPSIDE_COLOR); draw_seg_side(Groupsegp[current_group],Groupside[current_group]); } // Highlight marked segment and side. if (Markedsegp) { gr_setcolor(MARKEDSEG_COLOR); draw_segment(Markedsegp); gr_setcolor(MARKEDSIDE_COLOR); draw_seg_side(Markedsegp,Markedside); } // Highlight current segment and current side. gr_setcolor(CURSEG_COLOR); draw_segment(Cursegp); gr_setcolor(CURSIDE_COLOR); draw_seg_side(Cursegp,Curside); gr_setcolor(CUREDGE_COLOR); draw_side_edge(Cursegp,Curside,Curedge); // Draw coordinate axes if we are rendering the large view. if (Show_axes_flag) if (screen_canvas == LargeViewBox->canvas) draw_coordinate_axes(); // Label the window gr_set_fontcolor((v==current_view)?CRED:CWHITE, -1 ); if ( screen_canvas == LargeViewBox->canvas ) { gr_ustring( 5, 5, "USER VIEW" ); switch (Large_view_index) { case 0: gr_ustring( 85, 5, "-- TOP"); break; case 1: gr_ustring( 85, 5, "-- FRONT"); break; case 2: gr_ustring( 85, 5, "-- RIGHT"); break; } } else #if ORTHO_VIEWS else if ( screen_canvas == TopViewBox->canvas ) gr_ustring( 5, 5, "TOP" ); else if ( screen_canvas == FrontViewBox->canvas ) gr_ustring( 5, 5, "FRONT" ); else if ( screen_canvas == RightViewBox->canvas ) gr_ustring( 5, 5, "RIGHT" ); #else Error("Ortho views have been removed, what gives?\n"); #endif } g3_end_frame(); } //find the segments that render at a given screen x,y //parms other than x,y are like draw_world //fills in globals N_found_segs & Found_segs void find_segments(short x,short y,grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth) { vms_vector viewer_position; gr_set_current_canvas(screen_canvas); //g3_set_points(Segment_points,Vertices); viewer_position = v->ev_matrix.fvec; vm_vec_scale(&viewer_position,-v->ev_dist); vm_vec_add(&viewer_position,&viewer_position,&Ed_view_target); g3_start_frame(); g3_set_view_matrix(&viewer_position,&v->ev_matrix,v->ev_zoom); render_start_frame(); gr_setcolor(0); #ifdef OGL g3_end_frame(); #endif gr_pixel(x,y); //set our search pixel to color zero #ifdef OGL g3_start_frame(); #endif gr_setcolor(1); Search_mode = -1; N_found_segs = 0; Search_x = x; Search_y = y; if (Draw_all_segments) draw_mine_all(Segments, 0); else draw_mine(mine_ptr,depth); g3_end_frame(); Search_mode = 0; } void meddraw_init_views( grs_canvas * canvas) { Views[0]->ev_canv = canvas; #if ORTHO_VIEWS Views[1]->ev_canv = TopViewBox->canvas; Views[2]->ev_canv = FrontViewBox->canvas; Views[3]->ev_canv = RightViewBox->canvas; #endif } dxx-rebirth-0.58.1-d1x/editor/medmisc.c000066400000000000000000000324521217717257200176330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Miscellaneous functions stripped out of med.c * */ #include #include #include #include #include "gr.h" #include "ui.h" #include "3d.h" #include "u_mem.h" #include "dxxerror.h" #include "key.h" #include "mouse.h" #include "func.h" #include "inferno.h" #include "editor/editor.h" #include "editor/esegment.h" #include "segment.h" #include "render.h" #include "screens.h" #include "object.h" #include "texpage.h" // For texpage_goto_first #include "meddraw.h" // For draw_World #include "game.h" //return 2d distance, i.e, sqrt(x*x + y*y) #ifdef __WATCOMC__ long dist_2d(long x,long y); #pragma aux dist_2d parm [eax] [ebx] value [eax] modify [ecx edx] = \ "imul eax" \ "xchg ebx,eax" \ "mov ecx,edx" \ "imul eax" \ "add eax,ebx" \ "adc edx,ecx" \ "call quad_sqrt"; #else #include long dist_2d(long x,long y) { return (long)sqrt((double)x * (double)x + (double)y * (double)y); } #endif // Given mouse movement in dx, dy, returns a 3x3 rotation matrix in RotMat. // Taken from Graphics Gems III, page 51, "The Rolling Ball" void GetMouseRotation( int idx, int idy, vms_matrix * RotMat ) { fix dr, cos_theta, sin_theta, denom, cos_theta1; fix Radius = i2f(100); fix dx,dy; fix dxdr,dydr; idy *= -1; dx = i2f(idx); dy = i2f(idy); dr = dist_2d(dx,dy); denom = dist_2d(Radius,dr); cos_theta = fixdiv(Radius,denom); sin_theta = fixdiv(dr,denom); cos_theta1 = f1_0 - cos_theta; dxdr = fixdiv(dx,dr); dydr = fixdiv(dy,dr); RotMat->rvec.x = cos_theta + fixmul(fixmul(dydr,dydr),cos_theta1); RotMat->uvec.x = - fixmul(fixmul(dxdr,dydr),cos_theta1); RotMat->fvec.x = fixmul(dxdr,sin_theta); RotMat->rvec.y = RotMat->uvec.x; RotMat->uvec.y = cos_theta + fixmul(fixmul(dxdr,dxdr),cos_theta1); RotMat->fvec.y = fixmul(dydr,sin_theta); RotMat->rvec.z = -RotMat->fvec.x; RotMat->uvec.z = -RotMat->fvec.y; RotMat->fvec.z = cos_theta; } int Gameview_lockstep; //if set, view is locked to Curseg int ToggleLockstep() { Gameview_lockstep = !Gameview_lockstep; if (Gameview_lockstep == 0) { //if (keypress != KEY_L) diagnostic_message("[Ctrl-L] - Lock mode OFF"); //else // diagnostic_message("Lock mode OFF"); } if (Gameview_lockstep) { //if (keypress != KEY_L) diagnostic_message("[Ctrl-L] Lock mode ON"); //else // diagnostic_message("Lock mode ON"); Cursegp = &Segments[ConsoleObject->segnum]; med_create_new_segment_from_cursegp(); set_view_target_from_segment(Cursegp); Update_flags = UF_ED_STATE_CHANGED; } return Gameview_lockstep; } int medlisp_delete_segment(void) { if (!med_delete_segment(Cursegp)) { if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); autosave_mine(mine_filename); strcpy(undo_status[Autosave_count], "Delete Segment UNDONE."); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Segment deleted."); warn_if_concave_segments(); // This could be faster -- just check if deleted segment was concave, warn accordingly } return 1; } int medlisp_scale_segment(void) { vms_matrix rotmat; vms_vector scale; scale.x = fl2f((float) func_get_param(0)); scale.y = fl2f((float) func_get_param(1)); scale.z = fl2f((float) func_get_param(2)); med_create_new_segment(&scale); med_rotate_segment(Cursegp,vm_angles_2_matrix(&rotmat,&Seg_orientation)); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; return 1; } int medlisp_rotate_segment(void) { vms_matrix rotmat; Seg_orientation.p = func_get_param(0); Seg_orientation.b = func_get_param(1); Seg_orientation.h = func_get_param(2); med_rotate_segment(Cursegp,vm_angles_2_matrix(&rotmat,&Seg_orientation)); Update_flags |= UF_WORLD_CHANGED | UF_VIEWPOINT_MOVED; mine_changed = 1; return 1; } int ToggleLockViewToCursegp(void) { Lock_view_to_cursegp = !Lock_view_to_cursegp; Update_flags = UF_ED_STATE_CHANGED; if (Lock_view_to_cursegp) { //if (keypress != KEY_V+KEY_CTRLED) diagnostic_message("[ctrl-V] View locked to Cursegp."); //else // diagnostic_message("View locked to Cursegp."); set_view_target_from_segment(Cursegp); } else { //if (keypress != KEY_V+KEY_CTRLED) diagnostic_message("[ctrl-V] View not locked to Cursegp."); //else // diagnostic_message("View not locked to Cursegp."); } return Lock_view_to_cursegp; } int ToggleDrawAllSegments() { Draw_all_segments = !Draw_all_segments; Update_flags = UF_ED_STATE_CHANGED; if (Draw_all_segments == 1) { //if (keypress != KEY_A+KEY_CTRLED) diagnostic_message("[ctrl-A] Draw all segments ON."); //else // diagnostic_message("Draw all segments ON."); } if (Draw_all_segments == 0) { //if (keypress != KEY_A+KEY_CTRLED) diagnostic_message("[ctrl-A] Draw all segments OFF."); //else // diagnostic_message("Draw all segments OFF."); } return Draw_all_segments; } int Big_depth=6; int IncreaseDrawDepth(void) { Big_depth++; Update_flags = UF_ED_STATE_CHANGED; return 1; } int DecreaseDrawDepth(void) { if (Big_depth > 1) { Big_depth--; Update_flags = UF_ED_STATE_CHANGED; } return 1; } int ToggleCoordAxes() { // Toggle display of coordinate axes. Show_axes_flag = !Show_axes_flag; LargeView.ev_changed = 1; if (Show_axes_flag == 1) { //if (keypress != KEY_D+KEY_CTRLED) diagnostic_message("[ctrl-D] Coordinate axes ON."); //else // diagnostic_message("Coordinate axes ON."); } if (Show_axes_flag == 0) { //if (keypress != KEY_D+KEY_CTRLED) diagnostic_message("[ctrl-D] Coordinate axes OFF."); //else // diagnostic_message("Coordinate axes OFF."); } return Show_axes_flag; } int med_keypad_goto_prev() { ui_pad_goto_prev(); return 0; } int med_keypad_goto_next() { ui_pad_goto_next(); return 0; } int med_keypad_goto() { ui_pad_goto(func_get_param(0)); return 0; } int render_3d_in_big_window=0; int medlisp_update_screen() { int vn; #if 1 //def OGL Update_flags = UF_ALL; #endif if (!render_3d_in_big_window) for (vn=0;vnev_changed || (Update_flags & (UF_WORLD_CHANGED|UF_VIEWPOINT_MOVED|UF_ED_STATE_CHANGED))) { draw_world(Views[vn]->ev_canv,Views[vn],Cursegp,Big_depth); Views[vn]->ev_changed = 0; } if (Update_flags & (UF_WORLD_CHANGED|UF_GAME_VIEW_CHANGED|UF_ED_STATE_CHANGED)) { grs_canvas *render_canv,*show_canv; if (render_3d_in_big_window) { render_canv = LargeView.ev_canv; show_canv = LargeView.ev_canv; } else { render_canv = Canv_editor_game; show_canv = Canv_editor_game; } gr_set_current_canvas(render_canv); render_frame(0); Assert(render_canv->cv_bitmap.bm_w == show_canv->cv_bitmap.bm_w && render_canv->cv_bitmap.bm_h == show_canv->cv_bitmap.bm_h); (void)show_canv; } Update_flags=UF_NONE; //clear flags return 1; } void med_point_2_vec(grs_canvas *canv,vms_vector *v,short sx,short sy) { gr_set_current_canvas(canv); g3_start_frame(); g3_set_view_matrix(&Viewer->pos,&Viewer->orient,Render_zoom); g3_point_2_vec(v,sx,sy); g3_end_frame(); } void draw_world_from_game(void) { if (ModeFlag == 2) draw_world(Views[0]->ev_canv,Views[0],Cursegp,Big_depth); } int UndoCommand() { int u; u = undo(); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); if (u == 0) { if (Autosave_count==9) diagnostic_message(undo_status[0]); else diagnostic_message(undo_status[Autosave_count+1]); } else if (u == 1) diagnostic_message("Can't Undo."); else if (u == 2) diagnostic_message("Can't Undo - Autosave OFF"); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; warn_if_concave_segments(); return 1; } int ToggleAutosave() { Autosave_flag = !Autosave_flag; if (Autosave_flag == 1) diagnostic_message("Autosave ON."); else diagnostic_message("Autosave OFF."); return Autosave_flag; } int AttachSegment() { if (med_attach_segment(Cursegp, &New_segment, Curside, AttachSide)==4) // Used to be WBACK instead of Curside diagnostic_message("Cannot attach segment - already a connection on current side."); else { if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); vm_angvec_make(&Seg_orientation,0,0,0); Curside = WBACK; Update_flags |= UF_WORLD_CHANGED; autosave_mine(mine_filename); strcpy(undo_status[Autosave_count], "Attach Segment UNDONE.\n"); mine_changed = 1; warn_if_concave_segment(Cursegp); } return 1; } int ForceTotalRedraw() { Update_flags = UF_ALL; return 1; } #if ORTHO_VIEWS int SyncLargeView() { // Make large view be same as one of the orthogonal views. Large_view_index = (Large_view_index + 1) % 3; // keep in 0,1,2 for top, front, right switch (Large_view_index) { case 0: LargeView.ev_matrix = TopView.ev_matrix; break; case 1: LargeView.ev_matrix = FrontView.ev_matrix; break; case 2: LargeView.ev_matrix = RightView.ev_matrix; break; } Update_flags |= UF_VIEWPOINT_MOVED; return 1; } #endif int DeleteCurSegment() { // Delete current segment. med_delete_segment(Cursegp); autosave_mine(mine_filename); strcpy(undo_status[Autosave_count], "Delete segment UNDONE."); if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; diagnostic_message("Segment deleted."); warn_if_concave_segments(); // This could be faster -- just check if deleted segment was concave, warn accordingly return 1; } int CreateDefaultNewSegment() { // Create a default segment for New_segment. vms_vector tempvec; med_create_new_segment(vm_vec_make(&tempvec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE)); mine_changed = 1; return 1; } int CreateDefaultNewSegmentandAttach() { CreateDefaultNewSegment(); AttachSegment(); return 1; } int ExchangeMarkandCurseg() { // If Markedsegp != Cursegp, and Markedsegp->segnum != -1, exchange Markedsegp and Cursegp if (Markedsegp) if (Markedsegp->segnum != -1) { segment *tempsegp; int tempside; tempsegp = Markedsegp; Markedsegp = Cursegp; Cursegp = tempsegp; tempside = Markedside; Markedside = Curside; Curside = tempside; med_create_new_segment_from_cursegp(); Update_flags |= UF_ED_STATE_CHANGED; mine_changed = 1; } return 1; } int medlisp_add_segment() { AttachSegment(); //segment *ocursegp = Cursegp; // med_attach_segment(Cursegp, &New_segment, Curside, WFRONT); // Used to be WBACK instead of Curside //med_propagate_tmaps_to_segments(ocursegp,Cursegp); // set_view_target_from_segment(Cursegp); //// while (!vm_angvec_make(&Seg_orientation,0,0,0)); // Curside = WBACK; return 1; } int ClearSelectedList(void) { N_selected_segs = 0; Update_flags |= UF_WORLD_CHANGED; diagnostic_message("Selected list cleared."); return 1; } int ClearFoundList(void) { N_found_segs = 0; Update_flags |= UF_WORLD_CHANGED; diagnostic_message("Found list cleared."); return 1; } // --------------------------------------------------------------------------------------------------- // Do chase mode. // View current segment (Cursegp) from the previous segment. void set_chase_matrix(segment *sp) { int v; vms_vector forvec = ZERO_VECTOR, upvec; vms_vector tv = ZERO_VECTOR; segment *psp; // move back two segments, if possible, else move back one, if possible, else use current if (IS_CHILD(sp->children[WFRONT])) { psp = &Segments[sp->children[WFRONT]]; if (IS_CHILD(psp->children[WFRONT])) psp = &Segments[psp->children[WFRONT]]; } else psp = sp; for (v=0; vverts[v]]); vm_vec_scale(&forvec,F1_0/MAX_VERTICES_PER_SEGMENT); for (v=0; vverts[v]]); vm_vec_scale(&tv,F1_0/MAX_VERTICES_PER_SEGMENT); Ed_view_target = forvec; vm_vec_sub2(&forvec,&tv); extract_up_vector_from_segment(psp,&upvec); if (!((forvec.x == 0) && (forvec.y == 0) && (forvec.z == 0))) vm_vector_2_matrix(&LargeView.ev_matrix,&forvec,&upvec,NULL); } // --------------------------------------------------------------------------------------------------- void set_view_target_from_segment(segment *sp) { vms_vector tv = ZERO_VECTOR; int v; if (Funky_chase_mode) { //set_chase_matrix(sp); } else { for (v=0; vverts[v]]); vm_vec_scale(&tv,F1_0/MAX_VERTICES_PER_SEGMENT); Ed_view_target = tv; } Update_flags |= UF_VIEWPOINT_MOVED; } dxx-rebirth-0.58.1-d1x/editor/medrobot.c000066400000000000000000000611661217717257200200310ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Dialog box to edit robot properties. * */ #include #include #include #include #include "screens.h" #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "timer.h" #include "objpage.h" #include "fix.h" #include "dxxerror.h" #include "kdefs.h" #include "object.h" #include "polyobj.h" #include "game.h" #include "powerup.h" #include "ai.h" #include "hostage.h" #include "eobject.h" #include "medwall.h" #include "eswitch.h" #include "ehostage.h" #include "key.h" #include "centers.h" #include "bm.h" #define NUM_BOXES 6 // Number of boxes, AI modes int GoodyNextID(); int GoodyPrevID(); void robot_close_window(); //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- static UI_DIALOG *MainWindow = NULL; typedef struct robot_dialog { UI_GADGET_USERBOX *robotViewBox; UI_GADGET_USERBOX *containsViewBox; UI_GADGET_BUTTON *quitButton; UI_GADGET_RADIO *initialMode[NUM_BOXES]; int old_object; fix64 time; vms_angvec angles, goody_angles; } robot_dialog; //------------------------------------------------------------------------- // Given a pointer to an object, returns a number that cooresponds to the // object id as used in the objpage stuff. //------------------------------------------------------------------------- int get_object_id( object * obj ) { int i; int goal_type; switch( obj->type ) { case OBJ_PLAYER: goal_type=OL_PLAYER; break; case OBJ_ROBOT: goal_type=OL_ROBOT; break; case OBJ_POWERUP: goal_type=OL_POWERUP; break; case OBJ_CNTRLCEN: goal_type=OL_CONTROL_CENTER; break; case OBJ_HOSTAGE: goal_type=OL_HOSTAGE; break; case OBJ_CLUTTER: goal_type=OL_CLUTTER; break; default: Int3(); // Invalid object type return -1; } // Find first object with the same type as this // one and then add the object id to that to find // the offset into the list. for (i=0; i< Num_total_object_types; i++ ) { if ( ObjType[i]==goal_type) return obj->id + i; } return -1; } void call_init_ai_object(object *objp, int behavior) { int hide_segment; if (behavior == AIB_STATION) hide_segment = Cursegp-Segments; else { if (Markedsegp != NULL) hide_segment = Markedsegp-Segments; else hide_segment = Cursegp-Segments; } init_ai_object(objp-Objects, behavior, hide_segment); if (behavior == AIB_STATION) { objp->ctype.ai_info.follow_path_start_seg = Cursegp-Segments; objp->ctype.ai_info.follow_path_end_seg = Markedsegp-Segments; } } //------------------------------------------------------------------------- // Called when user presses "Next Type" button. This only works for polygon // objects and it just selects the next polygon model for the current object. //------------------------------------------------------------------------- int RobotNextType() { if (Cur_object_index > -1 ) { if ( Objects[Cur_object_index].type == OBJ_ROBOT ) { object * obj = &Objects[Cur_object_index]; obj->id++; if (obj->id >= N_robot_types ) obj->id = 0; //Set polygon-object-specific data obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; //set Physics info obj->mtype.phys_info.flags |= (PF_LEVELLING); obj->shields = Robot_info[obj->id].strength; call_init_ai_object(obj, AIB_NORMAL); Cur_object_id = obj->id; } } Update_flags |= UF_WORLD_CHANGED; return 1; } //------------------------------------------------------------------------- // Called when user presses "Prev Type" button. This only works for polygon // objects and it just selects the prev polygon model for the current object. //------------------------------------------------------------------------- int RobotPrevType() { if (Cur_object_index > -1 ) { if ( Objects[Cur_object_index].type == OBJ_ROBOT ) { object * obj = &Objects[Cur_object_index]; if (obj->id == 0 ) obj->id = N_robot_types-1; else obj->id--; //Set polygon-object-specific data obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; //set Physics info obj->mtype.phys_info.flags |= (PF_LEVELLING); obj->shields = Robot_info[obj->id].strength; call_init_ai_object(obj, AIB_NORMAL); Cur_object_id = obj->id; } } Update_flags |= UF_WORLD_CHANGED; return 1; } //------------------------------------------------------------------------- // Dummy function for Mike to write. //------------------------------------------------------------------------- int med_set_ai_path() { return 1; } // #define OBJ_NONE 255 //unused object // #define OBJ_WALL 0 //A wall... not really an object, but used for collisions // #define OBJ_FIREBALL 1 //a fireball, part of an explosion // #define OBJ_ROBOT 2 //an evil enemy // #define OBJ_HOSTAGE 3 //a hostage you need to rescue // #define OBJ_PLAYER 4 //the player on the console // #define OBJ_WEAPON 5 //a laser, missile, etc // #define OBJ_CAMERA 6 //a camera to slew around with // #define OBJ_POWERUP 7 //a powerup you can pick up // #define OBJ_DEBRIS 8 //a piece of robot // #define OBJ_CNTRLCEN 9 //the control center // #define OBJ_FLARE 10 //the control center // #define MAX_OBJECT_TYPES 11 #define GOODY_TYPE_MAX MAX_OBJECT_TYPES #define GOODY_X 6 #define GOODY_Y 132 //#define GOODY_ID_MAX_ROBOT 6 //#define GOODY_ID_MAX_POWERUP 9 #define GOODY_COUNT_MAX 4 int Cur_goody_type = OBJ_POWERUP; int Cur_goody_id = 0; int Cur_goody_count = 0; void update_goody_info(void) { if (Cur_object_index > -1 ) { if ( Objects[Cur_object_index].type == OBJ_ROBOT ) { object * obj = &Objects[Cur_object_index]; obj->contains_type = Cur_goody_type; obj->contains_id = Cur_goody_id; obj->contains_count = Cur_goody_count; } } } // #define OBJ_WALL 0 //A wall... not really an object, but used for collisions // #define OBJ_FIREBALL 1 //a fireball, part of an explosion // #define OBJ_ROBOT 2 //an evil enemy // #define OBJ_HOSTAGE 3 //a hostage you need to rescue // #define OBJ_PLAYER 4 //the player on the console // #define OBJ_WEAPON 5 //a laser, missile, etc // #define OBJ_CAMERA 6 //a camera to slew around with // #define OBJ_POWERUP 7 //a powerup you can pick up // #define OBJ_DEBRIS 8 //a piece of robot // #define OBJ_CNTRLCEN 9 //the control center // #define OBJ_FLARE 10 //the control center // #define MAX_OBJECT_TYPES 11 int GoodyNextType() { Cur_goody_type++; while (!((Cur_goody_type == OBJ_ROBOT) || (Cur_goody_type == OBJ_POWERUP))) { if (Cur_goody_type > GOODY_TYPE_MAX) Cur_goody_type=0; else Cur_goody_type++; } GoodyNextID(); GoodyPrevID(); update_goody_info(); return 1; } int GoodyPrevType() { Cur_goody_type--; while (!((Cur_goody_type == OBJ_ROBOT) || (Cur_goody_type == OBJ_POWERUP))) { if (Cur_goody_type < 0) Cur_goody_type = GOODY_TYPE_MAX; else Cur_goody_type--; } GoodyNextID(); GoodyPrevID(); update_goody_info(); return 1; } int GoodyNextID() { Cur_goody_id++; if (Cur_goody_type == OBJ_ROBOT) { if (Cur_goody_id >= N_robot_types) Cur_goody_id=0; } else { if (Cur_goody_id >= N_powerup_types) Cur_goody_id=0; } update_goody_info(); return 1; } int GoodyPrevID() { Cur_goody_id--; if (Cur_goody_type == OBJ_ROBOT) { if (Cur_goody_id < 0) Cur_goody_id = N_robot_types-1; } else { if (Cur_goody_id < 0) Cur_goody_id = N_powerup_types-1; } update_goody_info(); return 1; } int GoodyNextCount() { Cur_goody_count++; if (Cur_goody_count > GOODY_COUNT_MAX) Cur_goody_count=0; update_goody_info(); return 1; } int GoodyPrevCount() { Cur_goody_count--; if (Cur_goody_count < 0) Cur_goody_count=GOODY_COUNT_MAX; update_goody_info(); return 1; } int is_legal_type(int the_type) { return (the_type == OBJ_ROBOT) || (the_type == OBJ_CLUTTER); } int is_legal_type_for_this_window(int objnum) { if (objnum == -1) return 1; else return is_legal_type(Objects[objnum].type); } int LocalObjectSelectNextinSegment(void) { int rval, first_obj; rval = ObjectSelectNextinSegment(); first_obj = Cur_object_index; if (Cur_object_index != -1) { while (!is_legal_type_for_this_window(Cur_object_index)) { rval = ObjectSelectNextinSegment(); if (first_obj == Cur_object_index) break; } Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; if (Objects[Cur_object_index].contains_count < 0) Objects[Cur_object_index].contains_count = 0; Cur_goody_count = Objects[Cur_object_index].contains_count; } if (Cur_object_index != first_obj) set_view_target_from_segment(Cursegp); return rval; } int LocalObjectSelectNextinMine(void) { int rval, first_obj; rval = ObjectSelectNextInMine(); first_obj = Cur_object_index; if (Cur_object_index != -1) { while (!is_legal_type_for_this_window(Cur_object_index)) { ObjectSelectNextInMine(); if (Cur_object_index == first_obj) break; } Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; if (Objects[Cur_object_index].contains_count < 0) Objects[Cur_object_index].contains_count = 0; Cur_goody_count = Objects[Cur_object_index].contains_count; } if (Cur_object_index != first_obj) set_view_target_from_segment(Cursegp); return rval; } int LocalObjectSelectPrevinMine(void) { int rval, first_obj; rval = ObjectSelectPrevInMine(); first_obj = Cur_object_index; if (Cur_object_index != -1) { while (!is_legal_type_for_this_window(Cur_object_index)) { ObjectSelectPrevInMine(); if (first_obj == Cur_object_index) break; } Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; if (Objects[Cur_object_index].contains_count < 0) Objects[Cur_object_index].contains_count = 0; Cur_goody_count = Objects[Cur_object_index].contains_count; } if (Cur_object_index != first_obj) set_view_target_from_segment(Cursegp); return rval; } int LocalObjectDelete(void) { int rval; rval = ObjectDelete(); if (Cur_object_index != -1) { Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; Cur_goody_count = Objects[Cur_object_index].contains_count; } set_view_target_from_segment(Cursegp); return rval; } int LocalObjectPlaceObject(void) { int rval; Cur_goody_count = 0; if (Cur_object_type != OBJ_ROBOT) { Cur_object_type = OBJ_ROBOT; Cur_object_id = 3; // class 1 drone Num_object_subtypes = N_robot_types; } rval = ObjectPlaceObject(); if (rval == -1) return -1; Objects[Cur_object_index].contains_type = Cur_goody_type; Objects[Cur_object_index].contains_id = Cur_goody_id; Objects[Cur_object_index].contains_count = Cur_goody_count; set_view_target_from_segment(Cursegp); return rval; } void close_all_windows(void) { close_trigger_window(); close_wall_window(); close_centers_window(); hostage_close_window(); robot_close_window(); } int robot_dialog_handler(UI_DIALOG *dlg, d_event *event, robot_dialog *r); //------------------------------------------------------------------------- // Called from the editor... does one instance of the robot dialog box //------------------------------------------------------------------------- int do_robot_dialog() { int i; robot_dialog *r; // Only open 1 instance of this window... if ( MainWindow != NULL ) return 0; MALLOC(r, robot_dialog, 1); if (!r) return 0; // Close other windows close_all_windows(); Cur_goody_count = 0; memset(&r->angles, 0, sizeof(vms_angvec)); memset(&r->goody_angles, 0, sizeof(vms_angvec)); // Open a window with a quit button MainWindow = ui_create_dialog( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, (int (*)(UI_DIALOG *, d_event *, void *))robot_dialog_handler, r ); r->quitButton = ui_add_gadget_button( MainWindow, 20, 286, 40, 32, "Done", NULL ); ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y-3, 25, 22, "<<", GoodyPrevType ); ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y-3, 25, 22, ">>", GoodyNextType ); ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y+21, 25, 22, "<<", GoodyPrevID ); ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y+21, 25, 22, ">>", GoodyNextID ); ui_add_gadget_button( MainWindow, GOODY_X+50, GOODY_Y+45, 25, 22, "<<", GoodyPrevCount ); ui_add_gadget_button( MainWindow, GOODY_X+80, GOODY_Y+45, 25, 22, ">>", GoodyNextCount ); r->initialMode[0] = ui_add_gadget_radio( MainWindow, 6, 58, 16, 16, 0, "Hover" ); r->initialMode[1] = ui_add_gadget_radio( MainWindow, 76, 58, 16, 16, 0, "Normal" ); r->initialMode[2] = ui_add_gadget_radio( MainWindow, 6, 78, 16, 16, 0, "(hide)" ); r->initialMode[3] = ui_add_gadget_radio( MainWindow, 76, 78, 16, 16, 0, "Avoid" ); r->initialMode[4] = ui_add_gadget_radio( MainWindow, 6, 98, 16, 16, 0, "Follow" ); r->initialMode[5] = ui_add_gadget_radio( MainWindow, 76, 98, 16, 16, 0, "Station" ); // The little box the robots will spin in. r->robotViewBox = ui_add_gadget_userbox( MainWindow,155, 5, 150, 125 ); // The little box the robots will spin in. r->containsViewBox = ui_add_gadget_userbox( MainWindow,10, 202, 100, 80 ); // A bunch of buttons... i = 135; ui_add_gadget_button( MainWindow,190,i,53, 26, "<>", RobotNextType ); i += 29; ui_add_gadget_button( MainWindow,190,i,110, 26, "Next in Seg", LocalObjectSelectNextinSegment ); i += 29; ui_add_gadget_button( MainWindow,190,i,53, 26, "<>Obj", LocalObjectSelectNextinMine ); i += 29; ui_add_gadget_button( MainWindow,190,i,110, 26, "Delete", LocalObjectDelete ); i += 29; ui_add_gadget_button( MainWindow,190,i,110, 26, "Create New", LocalObjectPlaceObject ); i += 29; ui_add_gadget_button( MainWindow,190,i,110, 26, "Set Path", med_set_ai_path ); r->time = timer_query(); r->old_object = -2; // Set to some dummy value so everything works ok on the first frame. if ( Cur_object_index == -1 ) LocalObjectSelectNextinMine(); return 1; } void robot_close_window() { if ( MainWindow!=NULL ) { ui_close_dialog( MainWindow ); MainWindow = NULL; } } #define STRING_LENGTH 8 int robot_dialog_handler(UI_DIALOG *dlg, d_event *event, robot_dialog *r) { int i; fix DeltaTime; fix64 Temp; int first_object_index; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); Assert(MainWindow != NULL); first_object_index = Cur_object_index; while (!is_legal_type_for_this_window(Cur_object_index)) { LocalObjectSelectNextinMine(); if (first_object_index == Cur_object_index) { break; } } //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; //------------------------------------------------------------ // If we change objects, we need to reset the ui code for all // of the radio buttons that control the ai mode. Also makes // the current AI mode button be flagged as pressed down. //------------------------------------------------------------ if (r->old_object != Cur_object_index ) { for ( i=0; i < NUM_BOXES; i++ ) ui_radio_set_value(r->initialMode[i], 0); if ( Cur_object_index > -1 ) { int behavior = Objects[Cur_object_index].ctype.ai_info.behavior; if ( !((behavior >= MIN_BEHAVIOR) && (behavior <= MAX_BEHAVIOR))) { Objects[Cur_object_index].ctype.ai_info.behavior = AIB_NORMAL; behavior = AIB_NORMAL; } ui_radio_set_value(r->initialMode[behavior - MIN_BEHAVIOR], 1); } } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the cooresponding AI state. //------------------------------------------------------------ for ( i=0; i < NUM_BOXES; i++ ) { if ( GADGET_PRESSED(r->initialMode[i]) ) if (Objects[Cur_object_index].ctype.ai_info.behavior != MIN_BEHAVIOR+i) { Objects[Cur_object_index].ctype.ai_info.behavior = MIN_BEHAVIOR+i; // Set the ai_state to the cooresponding radio button call_init_ai_object(&Objects[Cur_object_index], MIN_BEHAVIOR+i); rval = 1; } } //------------------------------------------------------------ // Redraw the object in the little 64x64 box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { // A simple frame time counter for spinning the objects... Temp = timer_query(); DeltaTime = Temp - r->time; r->time = Temp; if (Cur_object_index > -1 ) { object *obj = &Objects[Cur_object_index]; gr_set_current_canvas( r->robotViewBox->canvas ); draw_object_picture(obj->id, &r->angles, obj->type ); r->angles.h += fixmul(0x1000, DeltaTime ); } else { // no object, so just blank out gr_set_current_canvas( r->robotViewBox->canvas ); gr_clear_canvas( CGREY ); // LocalObjectSelectNextInMine(); } } //------------------------------------------------------------ // Redraw the contained object in the other little box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { if ((Cur_object_index > -1 ) && (Cur_goody_count > 0)) { gr_set_current_canvas( r->containsViewBox->canvas ); if ( Cur_goody_id > -1 ) draw_object_picture(Cur_goody_id, &r->goody_angles, Cur_goody_type); else gr_clear_canvas( CGREY ); r->goody_angles.h += fixmul(0x1000, DeltaTime ); } else { // no object, so just blank out gr_set_current_canvas( r->containsViewBox->canvas ); gr_clear_canvas( CGREY ); // LocalObjectSelectNextInMine(); } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { int i; char id_text[STRING_LENGTH+1]; const char *type_text; if (Cur_object_index != -1) { Cur_goody_type = Objects[Cur_object_index].contains_type; Cur_goody_id = Objects[Cur_object_index].contains_id; if (Objects[Cur_object_index].contains_count < 0) Objects[Cur_object_index].contains_count = 0; Cur_goody_count = Objects[Cur_object_index].contains_count; } ui_dprintf_at( MainWindow, GOODY_X, GOODY_Y, " Type:"); ui_dprintf_at( MainWindow, GOODY_X, GOODY_Y+24, " ID:"); ui_dprintf_at( MainWindow, GOODY_X, GOODY_Y+48, "Count:"); for (i=0; i -1 ) { int id = Objects[Cur_object_index].id; char id_text[12]; int i; for (i=0; iold_object != Cur_object_index) ) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(r); MainWindow = NULL; return 0; } if ( GADGET_PRESSED(r->quitButton) || (keypress==KEY_ESC)) { robot_close_window(); return 1; } r->old_object = Cur_object_index; return rval; } // -------------------------------------------------------------------------------------------------------------------------- #define NUM_MATT_THINGS 2 #define MATT_LEN 20 static UI_DIALOG *MattWindow = NULL; typedef struct object_dialog { UI_GADGET_INPUTBOX *xtext, *ytext, *ztext; UI_GADGET_RADIO *initialMode[2]; UI_GADGET_BUTTON *quitButton; } object_dialog; void object_close_window() { if ( MattWindow!=NULL ) { ui_close_dialog( MattWindow ); MattWindow = NULL; } } int object_dialog_handler(UI_DIALOG *dlg, d_event *event, object_dialog *o); //------------------------------------------------------------------------- // Called from the editor... does one instance of the object dialog box //------------------------------------------------------------------------- int do_object_dialog() { char Xmessage[MATT_LEN], Ymessage[MATT_LEN], Zmessage[MATT_LEN]; object *obj=&Objects[Cur_object_index]; object_dialog *o; if (obj->type == OBJ_ROBOT) //don't do this for robots return 0; // Only open 1 instance of this window... if ( MattWindow != NULL ) return 0; MALLOC(o, object_dialog, 1); if (!o) return 0; Cur_goody_count = 0; // Open a window with a quit button MattWindow = ui_create_dialog( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, (int (*)(UI_DIALOG *, d_event *, void *))object_dialog_handler, o ); o->quitButton = ui_add_gadget_button( MattWindow, 20, 286, 40, 32, "Done", NULL ); o->quitButton->hotkey = KEY_ENTER; // These are the radio buttons for each mode o->initialMode[0] = ui_add_gadget_radio( MattWindow, 10, 50, 16, 16, 0, "None" ); o->initialMode[1] = ui_add_gadget_radio( MattWindow, 80, 50, 16, 16, 0, "Spinning" ); o->initialMode[obj->movement_type == MT_SPINNING?1:0]->flag = 1; sprintf(Xmessage,"%.2f",f2fl(obj->mtype.spin_rate.x)); sprintf(Ymessage,"%.2f",f2fl(obj->mtype.spin_rate.y)); sprintf(Zmessage,"%.2f",f2fl(obj->mtype.spin_rate.z)); o->xtext = ui_add_gadget_inputbox( MattWindow, 30, 132, MATT_LEN, MATT_LEN, Xmessage ); o->ytext = ui_add_gadget_inputbox( MattWindow, 30, 162, MATT_LEN, MATT_LEN, Ymessage ); o->ztext = ui_add_gadget_inputbox( MattWindow, 30, 192, MATT_LEN, MATT_LEN, Zmessage ); ui_gadget_calc_keys(MattWindow); MattWindow->keyboard_focus_gadget = (UI_GADGET *) o->initialMode[0]; return 1; } int object_dialog_handler(UI_DIALOG *dlg, d_event *event, object_dialog *o) { object *obj=&Objects[Cur_object_index]; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); Assert(MattWindow != NULL); //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; if (event->type == EVENT_WINDOW_CLOSE) { d_free(o); MattWindow = NULL; return 0; } else if (event->type == EVENT_UI_DIALOG_DRAW) { ui_dprintf_at( MattWindow, 10, 132,"&X:" ); ui_dprintf_at( MattWindow, 10, 162,"&Y:" ); ui_dprintf_at( MattWindow, 10, 192,"&Z:" ); } if ( GADGET_PRESSED(o->quitButton) || (keypress==KEY_ESC)) { if (o->initialMode[0]->flag) obj->movement_type = MT_NONE; if (o->initialMode[1]->flag) obj->movement_type = MT_SPINNING; obj->mtype.spin_rate.x = fl2f(atof(o->xtext->text)); obj->mtype.spin_rate.y = fl2f(atof(o->ytext->text)); obj->mtype.spin_rate.z = fl2f(atof(o->ztext->text)); object_close_window(); return 1; } return rval; } void set_all_modes_to_hover(void) { int i; for (i=0; i<=Highest_object_index; i++) if (Objects[i].control_type == CT_AI) Objects[i].ctype.ai_info.behavior = AIB_STILL; } dxx-rebirth-0.58.1-d1x/editor/medsel.c000066400000000000000000000057421217717257200174650ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines stripped from med.c for segment selection * */ #include #include #include #include #include "gr.h" #include "ui.h" #include "key.h" #include "dxxerror.h" #include "u_mem.h" #include "inferno.h" #include "editor.h" #include "editor/esegment.h" #include "segment.h" #include "object.h" typedef struct sort_element { short segnum; fix dist; } sort_element; //compare the distance of two segments. slow, since it computes the //distance each time int segdist_cmp(sort_element *s0,sort_element *s1) { return (s0->dist==s1->dist)?0:((s0->distdist)?-1:1); } //find the distance between a segment and a point fix compute_dist(segment *seg,vms_vector *pos) { vms_vector delta; compute_segment_center(&delta,seg); vm_vec_sub2(&delta,pos); return vm_vec_mag(&delta); } //sort a list of segments, in order of closeness to pos void sort_seg_list(int n_segs,short *segnumlist,vms_vector *pos) { int i; sort_element *sortlist; sortlist = d_calloc(n_segs, sizeof(*sortlist)); for (i=0;ipos); editor_status_fmt("%i element selected list sorted.",N_selected_segs); return 1; } int SelectNextFoundSeg(void) { if (++Found_seg_index >= N_found_segs) Found_seg_index = 0; Cursegp = &Segments[Found_segs[Found_seg_index]]; med_create_new_segment_from_cursegp(); Update_flags |= UF_WORLD_CHANGED; if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); editor_status("Curseg assigned to next found segment."); return 1; } int SelectPreviousFoundSeg(void) { if (Found_seg_index > 0) Found_seg_index--; else Found_seg_index = N_found_segs-1; Cursegp = &Segments[Found_segs[Found_seg_index]]; med_create_new_segment_from_cursegp(); Update_flags |= UF_WORLD_CHANGED; if (Lock_view_to_cursegp) set_view_target_from_segment(Cursegp); editor_status("Curseg assigned to previous found segment."); return 1; } dxx-rebirth-0.58.1-d1x/editor/medwall.c000066400000000000000000001104701217717257200176340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Created from version 1.11 of main\wall.c * */ #include #include #include #include #include "editor/medwall.h" #include "inferno.h" #include "editor/editor.h" #include "editor/esegment.h" #include "segment.h" #include "dxxerror.h" #include "gameseg.h" #include "textures.h" #include "screens.h" #include "switch.h" #include "editor/eswitch.h" #include "texmerge.h" #include "medrobot.h" #include "timer.h" #include "cntrlcen.h" #include "key.h" #include "ehostage.h" #include "centers.h" #include "piggy.h" int wall_add_door_flag(sbyte flag); int wall_add_to_side(segment *segp, int side, sbyte type); int wall_remove_door_flag(sbyte flag); //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- static UI_DIALOG *MainWindow = NULL; typedef struct wall_dialog { UI_GADGET_USERBOX *wallViewBox; UI_GADGET_BUTTON *quitButton; UI_GADGET_CHECKBOX *doorFlag[4]; UI_GADGET_RADIO *keyFlag[4]; int old_wall_num; fix64 time; int framenum; } wall_dialog; static int Current_door_type=1; typedef struct count_wall { short wallnum; short segnum,sidenum; } count_wall; //--------------------------------------------------------------------- // Add a wall (removable 2 sided) int add_wall(segment *seg, short side) { int Connectside; segment *csegp; if (Num_walls < MAX_WALLS-2) if (IS_CHILD(seg->children[side])) { if (seg->sides[side].wall_num == -1) { seg->sides[side].wall_num = Num_walls; Num_walls++; } csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); if (csegp->sides[Connectside].wall_num == -1) { csegp->sides[Connectside].wall_num = Num_walls; Num_walls++; } create_removable_wall( seg, side, CurrentTexture ); create_removable_wall( csegp, Connectside, CurrentTexture ); return 1; } return 0; } int wall_assign_door(int door_type) { int Connectside; segment *csegp; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("Cannot assign door. No wall at Curside."); return 0; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) { editor_status("Cannot assign door. No door at Curside."); return 0; } Current_door_type = door_type; csegp = &Segments[Cursegp->children[Curside]]; Connectside = find_connect_side(Cursegp, csegp); Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type; Walls[csegp->sides[Connectside].wall_num].clip_num = door_type; if (WallAnims[door_type].flags & WCF_TMAP1) { Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0]; csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0]; Cursegp->sides[Curside].tmap_num2 = 0; csegp->sides[Connectside].tmap_num2 = 0; } else { Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0]; csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0]; } Update_flags |= UF_WORLD_CHANGED; return 1; } int wall_add_blastable() { return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE); } int wall_add_door() { return wall_add_to_side(Cursegp, Curside, WALL_DOOR); } int wall_add_closed_wall() { return wall_add_to_side(Cursegp, Curside, WALL_CLOSED); } int wall_add_external_wall() { if (Cursegp->children[Curside] == -2) { editor_status( "Wall is already external!" ); return 1; } if (IS_CHILD(Cursegp->children[Curside])) { editor_status( "Cannot add external wall here - seg has children" ); return 0; } Cursegp->children[Curside] = -2; return 1; } int wall_add_illusion() { return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION); } int wall_lock_door() { return wall_add_door_flag(WALL_DOOR_LOCKED); } int wall_unlock_door() { return wall_remove_door_flag(WALL_DOOR_LOCKED); } int wall_automate_door() { return wall_add_door_flag(WALL_DOOR_AUTO); } int wall_deautomate_door() { return wall_remove_door_flag(WALL_DOOR_AUTO); } int GotoPrevWall() { int current_wall; if (Cursegp->sides[Curside].wall_num < 0) current_wall = Num_walls; else current_wall = Cursegp->sides[Curside].wall_num; current_wall--; if (current_wall < 0) current_wall = Num_walls-1; if (current_wall >= Num_walls) current_wall = Num_walls-1; if (Walls[current_wall].segnum == -1) { return 0; } if (Walls[current_wall].sidenum == -1) { return 0; } Cursegp = &Segments[Walls[current_wall].segnum]; Curside = Walls[current_wall].sidenum; return 1; } int GotoNextWall() { int current_wall; current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0 current_wall++; if (current_wall >= Num_walls) current_wall = 0; if (current_wall < 0) current_wall = 0; if (Walls[current_wall].segnum == -1) { return 0; } if (Walls[current_wall].sidenum == -1) { return 0; } Cursegp = &Segments[Walls[current_wall].segnum]; Curside = Walls[current_wall].sidenum; return 1; } int PrevWall() { int wall_type; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("Cannot assign new wall. No wall on curside."); return 0; } wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num; if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { do { wall_type--; if (wall_type < 0) wall_type = Num_wall_anims-1; if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num) Error("Cannot find clip for door."); } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE); } else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) { do { wall_type--; if (wall_type < 0) wall_type = Num_wall_anims-1; if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num) Error("Cannot find clip for blastable wall."); } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE)); } wall_assign_door(wall_type); Update_flags |= UF_WORLD_CHANGED; return 1; } int NextWall() { int wall_type; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("Cannot assign new wall. No wall on curside."); return 0; } wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num; if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { do { wall_type++; if (wall_type >= Num_wall_anims) { wall_type = 0; if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1) Error("Cannot find clip for door."); } } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE); } else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) { do { wall_type++; if (wall_type >= Num_wall_anims) { wall_type = 0; if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1) Error("Cannot find clip for blastable wall."); } } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE)); } wall_assign_door(wall_type); Update_flags |= UF_WORLD_CHANGED; return 1; } int wall_dialog_handler(UI_DIALOG *dlg, d_event *event, wall_dialog *wd); //------------------------------------------------------------------------- // Called from the editor... does one instance of the wall dialog box //------------------------------------------------------------------------- int do_wall_dialog() { int i; wall_dialog *wd; // Only open 1 instance of this window... if ( MainWindow != NULL ) return 0; MALLOC(wd, wall_dialog, 1); if (!wd) return 0; wd->framenum = 0; // Close other windows. close_all_windows(); // Open a window with a quit button MainWindow = ui_create_dialog( TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, (int (*)(UI_DIALOG *, d_event *, void *))wall_dialog_handler, wd ); wd->quitButton = ui_add_gadget_button( MainWindow, 20, 252, 48, 40, "Done", NULL ); // These are the checkboxes for each door flag. i = 80; wd->doorFlag[0] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Locked" ); i += 24; wd->doorFlag[1] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Auto" ); i += 24; wd->doorFlag[2] = ui_add_gadget_checkbox( MainWindow, 22, i, 16, 16, 0, "Illusion OFF" ); i += 24; wd->keyFlag[0] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "NONE" ); i += 24; wd->keyFlag[1] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Blue" ); i += 24; wd->keyFlag[2] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Red" ); i += 24; wd->keyFlag[3] = ui_add_gadget_radio( MainWindow, 22, i, 16, 16, 0, "Yellow" ); i += 24; // The little box the wall will appear in. wd->wallViewBox = ui_add_gadget_userbox( MainWindow, 155, 5, 64, 64 ); // A bunch of buttons... i = 80; ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Clip", PrevWall ); ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Clip >>", NextWall );i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Blastable", wall_add_blastable ); i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Door", wall_add_door ); i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Illusory", wall_add_illusion); i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Add Closed Wall", wall_add_closed_wall ); i+=25; // ui_add_gadget_button( MainWindow,155,i,140, 22, "Restore All Walls", wall_restore_all ); i += 25; ui_add_gadget_button( MainWindow,155,i,70, 22, "<< Prev", GotoPrevWall ); ui_add_gadget_button( MainWindow,155+70,i,70, 22, "Next >>", GotoNextWall );i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Remove Wall", wall_remove ); i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Trigger", bind_wall_to_trigger ); i += 25; ui_add_gadget_button( MainWindow,155,i,140, 22, "Bind to Control", bind_wall_to_control_center ); i+=25; wd->old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame. return 1; } void close_wall_window() { if ( MainWindow!=NULL ) { ui_close_dialog( MainWindow ); MainWindow = NULL; } } int wall_dialog_handler(UI_DIALOG *dlg, d_event *event, wall_dialog *wd) { int i; sbyte type; fix DeltaTime; fix64 Temp; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); Assert(MainWindow != NULL); //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; //------------------------------------------------------------ // If we change walls, we need to reset the ui code for all // of the checkboxes that control the wall flags. //------------------------------------------------------------ if (wd->old_wall_num != Cursegp->sides[Curside].wall_num) { if ( Cursegp->sides[Curside].wall_num != -1) { wall *w = &Walls[Cursegp->sides[Curside].wall_num]; ui_checkbox_check(wd->doorFlag[0], w->flags & WALL_DOOR_LOCKED); ui_checkbox_check(wd->doorFlag[1], w->flags & WALL_DOOR_AUTO); ui_checkbox_check(wd->doorFlag[2], w->flags & WALL_ILLUSION_OFF); ui_radio_set_value(wd->keyFlag[0], w->keys & KEY_NONE); ui_radio_set_value(wd->keyFlag[1], w->keys & KEY_BLUE); ui_radio_set_value(wd->keyFlag[2], w->keys & KEY_RED); ui_radio_set_value(wd->keyFlag[3], w->keys & KEY_GOLD); } } //------------------------------------------------------------ // If any of the checkboxes that control the wallflags are set, then // update the corresponding wall flag. //------------------------------------------------------------ if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { if (GADGET_PRESSED(wd->doorFlag[0])) { if ( wd->doorFlag[0]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED; rval = 1; } else if (GADGET_PRESSED(wd->doorFlag[1])) { if ( wd->doorFlag[1]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO; rval = 1; } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the corresponding key. //------------------------------------------------------------ for ( i=0; i < 4; i++ ) { if (GADGET_PRESSED(wd->keyFlag[i])) { Walls[Cursegp->sides[Curside].wall_num].keys = 1<doorFlag[i], 0); for ( i=0; i < 4; i++ ) ui_radio_set_value(wd->keyFlag[i], 0); } if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) { if (GADGET_PRESSED(wd->doorFlag[2])) { if ( wd->doorFlag[2]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF; rval = 1; } } else for ( i=2; i < 3; i++ ) if (wd->doorFlag[i]->flag == 1) { wd->doorFlag[i]->flag = 0; // Tells ui that this button isn't checked wd->doorFlag[i]->status = 1; // Tells ui to redraw button } //------------------------------------------------------------ // Draw the wall in the little 64x64 box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { // A simple frame time counter for animating the walls... Temp = timer_query(); DeltaTime = Temp - wd->time; gr_set_current_canvas( wd->wallViewBox->canvas ); if (Cursegp->sides[Curside].wall_num != -1) { type = Walls[Cursegp->sides[Curside].wall_num].type; if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) { if (DeltaTime > ((F1_0*200)/1000)) { wd->framenum++; wd->time = Temp; } if (wd->framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames) wd->framenum=0; PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[wd->framenum]]); gr_ubitmap(0,0, &GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[wd->framenum]].index]); } else { if (type == WALL_OPEN) gr_clear_canvas( CBLACK ); else { if (Cursegp->sides[Curside].tmap_num2 > 0) gr_ubitmap(0,0, texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2)); else { PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]); gr_ubitmap(0,0, &GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]); } } } } else gr_clear_canvas( CGREY ); } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this wall. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { if ( Cursegp->sides[Curside].wall_num > -1 ) { ui_dprintf_at( MainWindow, 12, 6, "Wall: %d ", Cursegp->sides[Curside].wall_num); switch (Walls[Cursegp->sides[Curside].wall_num].type) { case WALL_NORMAL: ui_dprintf_at( MainWindow, 12, 23, " Type: Normal " ); break; case WALL_BLASTABLE: ui_dprintf_at( MainWindow, 12, 23, " Type: Blastable" ); break; case WALL_DOOR: ui_dprintf_at( MainWindow, 12, 23, " Type: Door " ); ui_dprintf_at( MainWindow, 223, 6, "%s", WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename); break; case WALL_ILLUSION: ui_dprintf_at( MainWindow, 12, 23, " Type: Illusion " ); break; case WALL_OPEN: ui_dprintf_at( MainWindow, 12, 23, " Type: Open " ); break; case WALL_CLOSED: ui_dprintf_at( MainWindow, 12, 23, " Type: Closed " ); break; default: ui_dprintf_at( MainWindow, 12, 23, " Type: Unknown " ); break; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR) ui_dprintf_at( MainWindow, 223, 6, " " ); ui_dprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num ); ui_dprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger ); } else { ui_dprintf_at( MainWindow, 12, 6, "Wall: none "); ui_dprintf_at( MainWindow, 12, 23, " Type: none "); ui_dprintf_at( MainWindow, 12, 40, " Clip: none "); ui_dprintf_at( MainWindow, 12, 57, " Trigger: none "); } } if (ui_button_any_drawn || (wd->old_wall_num != Cursegp->sides[Curside].wall_num) ) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(wd); MainWindow = NULL; return 0; } if ( GADGET_PRESSED(wd->quitButton) || (keypress==KEY_ESC) ) { close_wall_window(); return 1; } wd->old_wall_num = Cursegp->sides[Curside].wall_num; return rval; } //--------------------------------------------------------------------- // Restore all walls to original status (closed doors, repaired walls) int wall_restore_all() { int i, j; int wall_num; for (i=0;i wall_num) Segments[seg].sides[side].wall_num--; return 1; } //--------------------------------------------------------------------- // Remove a specific side. int wall_remove_side(segment *seg, short side) { int Connectside; segment *csegp; int lower_wallnum; int w, s, t, l, t1; if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) { csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); remove_trigger(seg, side); remove_trigger(csegp, Connectside); // Remove walls 'wall_num' and connecting side 'wall_num' // from Walls array. lower_wallnum = seg->sides[side].wall_num; if (csegp->sides[Connectside].wall_num < lower_wallnum) lower_wallnum = csegp->sides[Connectside].wall_num; if (Walls[lower_wallnum].linked_wall != -1) Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1; if (Walls[lower_wallnum+1].linked_wall != -1) Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1; for (w=lower_wallnum;w lower_wallnum+1) Segments[s].sides[w].wall_num -= 2; // Destroy any links to the deleted wall. for (t=0;tsides[side].wall_num = -1; csegp->sides[Connectside].wall_num = -1; Update_flags |= UF_WORLD_CHANGED; return 1; } editor_status( "Can't remove wall. No wall present."); return 0; } //--------------------------------------------------------------------- // Remove a special wall. int wall_remove() { return wall_remove_side(Cursegp, Curside); } //--------------------------------------------------------------------- // Add a wall to curside int wall_add_to_side(segment *segp, int side, sbyte type) { int connectside; segment *csegp; if (add_wall(segp, side)) { csegp = &Segments[segp->children[side]]; connectside = find_connect_side(segp, csegp); Walls[segp->sides[side].wall_num].segnum = segp-Segments; Walls[csegp->sides[connectside].wall_num].segnum = csegp-Segments; Walls[segp->sides[side].wall_num].sidenum = side; Walls[csegp->sides[connectside].wall_num].sidenum = connectside; Walls[segp->sides[side].wall_num].flags = 0; Walls[csegp->sides[connectside].wall_num].flags = 0; Walls[segp->sides[side].wall_num].type = type; Walls[csegp->sides[connectside].wall_num].type = type; // Walls[segp->sides[side].wall_num].trigger = -1; // Walls[csegp->sides[connectside].wall_num].trigger = -1; Walls[segp->sides[side].wall_num].clip_num = -1; Walls[csegp->sides[connectside].wall_num].clip_num = -1; Walls[segp->sides[side].wall_num].keys = KEY_NONE; Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE; if (type == WALL_BLASTABLE) { Walls[segp->sides[side].wall_num].hps = WALL_HPS; Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS; //Walls[segp->sides[side].wall_num].clip_num = 0; //Walls[csegp->sides[connectside].wall_num].clip_num = 0; } if (type != WALL_DOOR) { segp->sides[side].tmap_num2 = 0; csegp->sides[connectside].tmap_num2 = 0; } if (type == WALL_DOOR) { Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO; Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO; Walls[segp->sides[side].wall_num].clip_num = Current_door_type; Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type; } //Update_flags |= UF_WORLD_CHANGED; //return 1; // return NextWall(); //assign a clip num return wall_assign_door(Current_door_type); } else { editor_status( "Cannot add wall here, no children" ); return 0; } } //--------------------------------------------------------------------- // Add a wall to markedside int wall_add_to_markedside(sbyte type) { int Connectside; segment *csegp; if (add_wall(Markedsegp, Markedside)) { int wall_num, cwall_num; csegp = &Segments[Markedsegp->children[Markedside]]; Connectside = find_connect_side(Markedsegp, csegp); wall_num = Markedsegp->sides[Markedside].wall_num; cwall_num = csegp->sides[Connectside].wall_num; Walls[wall_num].segnum = Markedsegp-Segments; Walls[cwall_num].segnum = csegp-Segments; Walls[wall_num].sidenum = Markedside; Walls[cwall_num].sidenum = Connectside; Walls[wall_num].flags = 0; Walls[cwall_num].flags = 0; Walls[wall_num].type = type; Walls[cwall_num].type = type; Walls[wall_num].trigger = -1; Walls[cwall_num].trigger = -1; Walls[wall_num].clip_num = -1; Walls[cwall_num].clip_num = -1; Walls[wall_num].keys = KEY_NONE; Walls[cwall_num].keys = KEY_NONE; if (type == WALL_BLASTABLE) { Walls[wall_num].hps = WALL_HPS; Walls[cwall_num].hps = WALL_HPS; Walls[wall_num].clip_num = 0; Walls[cwall_num].clip_num = 0; } if (type != WALL_DOOR) { Markedsegp->sides[Markedside].tmap_num2 = 0; csegp->sides[Connectside].tmap_num2 = 0; } Update_flags |= UF_WORLD_CHANGED; return 1; } else { editor_status( "Cannot add wall here, no children" ); return 0; } } int wall_add_door_flag(sbyte flag) { int Connectside; segment *csegp; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("Cannot change flag. No wall at Curside."); return 0; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR) { editor_status("Cannot change flag. No door at Curside."); return 0; } csegp = &Segments[Cursegp->children[Curside]]; Connectside = find_connect_side(Cursegp, csegp); Walls[Cursegp->sides[Curside].wall_num].flags |= flag; Walls[csegp->sides[Connectside].wall_num].flags |= flag; Update_flags |= UF_ED_STATE_CHANGED; return 1; } int wall_remove_door_flag(sbyte flag) { int Connectside; segment *csegp; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("Cannot change flag. No wall at Curside."); return 0; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR) { editor_status("Cannot change flag. No door at Curside."); return 0; } csegp = &Segments[Cursegp->children[Curside]]; Connectside = find_connect_side(Cursegp, csegp); Walls[Cursegp->sides[Curside].wall_num].flags &= ~flag; Walls[csegp->sides[Connectside].wall_num].flags &= ~flag; Update_flags |= UF_ED_STATE_CHANGED; return 1; } int bind_wall_to_control_center() { int link_num; int i; if (Cursegp->sides[Curside].wall_num == -1) { editor_status("No wall at Curside."); return 0; } link_num = ControlCenterTriggers.num_links; for (i=0;isides[Curside].wall_num != -1) w1 = &Walls[Cursegp->sides[Curside].wall_num]; if (Markedsegp->sides[Markedside].wall_num != -1) w2 = &Walls[Markedsegp->sides[Markedside].wall_num]; if (!w1 || w1->type != WALL_DOOR) { editor_status("Curseg/curside is not a door"); return 0; } if (!w2 || w2->type != WALL_DOOR) { editor_status("Markedseg/markedside is not a door"); return 0; } if (w1->linked_wall != -1) editor_status("Curseg/curside is already linked"); if (w2->linked_wall != -1) editor_status("Markedseg/markedside is already linked"); w1->linked_wall = w2-Walls; w2->linked_wall = w1-Walls; return 1; } int wall_unlink_door() { wall *w1=NULL; if (Cursegp->sides[Curside].wall_num != -1) w1 = &Walls[Cursegp->sides[Curside].wall_num]; if (!w1 || w1->type != WALL_DOOR) { editor_status("Curseg/curside is not a door"); return 0; } if (w1->linked_wall == -1) editor_status("Curseg/curside is not linked"); Assert(Walls[w1->linked_wall].linked_wall == w1-Walls); Walls[w1->linked_wall].linked_wall = -1; w1->linked_wall = -1; return 1; } #define DIAGNOSTIC_MESSAGE_MAX 150 int check_walls() { int w, seg, side, wall_count, trigger_count; int w1; count_wall CountedWalls[MAX_WALLS]; char Message[DIAGNOSTIC_MESSAGE_MAX]; int matcen_num; wall_count = 0; for (seg=0;seg<=Highest_segment_index;seg++) if (Segments[seg].segnum != -1) { // Check fuelcenters matcen_num = Segments[seg].matcen_num; if (matcen_num == 0) if (RobotCenters[0].segnum != seg) { Segments[seg].matcen_num = -1; } if (matcen_num > -1) if (RobotCenters[matcen_num].segnum != seg) { RobotCenters[matcen_num].segnum = seg; } for (side=0;side #include #include #include #include "physfsx.h" #include "key.h" #include "gr.h" #include "bm.h" // for MAX_TEXTURES #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "textures.h" #include "object.h" #include "gamemine.h" #include "gamesave.h" #include "gameseg.h" #include "ui.h" // Because texpage.h need UI_DIALOG type #include "texpage.h" // For texpage_goto_first #include "medwall.h" #include "switch.h" #include "fuelcen.h" #define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0') int CreateDefaultNewSegment(); int save_mine_data(PHYSFS_file * SaveFile); static char current_tmap_list[MAX_TEXTURES][13]; int New_file_format_save = 1; // ----------------------------------------------------------------------------- // Save mine will: // 1. Write file info, header info, editor info, vertex data, segment data, // and new_segment in that order, marking their file offset. // 2. Go through all the fields and fill in the offset, size, and sizeof // values in the headers. int med_save_mine(char * filename) { PHYSFS_file *SaveFile; char ErrorMessage[256]; SaveFile = PHYSFSX_openWriteBuffered( filename ); if (!SaveFile) { #if 0 //ndef __linux__ char fname[20]; d_splitpath( filename, NULL, NULL, fname, NULL ); sprintf( ErrorMessage, \ "ERROR: Cannot write to '%s'.\nYou probably need to check out a locked\nversion of the file. You should save\nthis under a different filename, and then\ncheck out a locked copy by typing\n\'co -l %s.lvl'\nat the DOS prompt.\n" , filename, fname); #endif sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename ); ui_messagebox( -2, -2, 1, ErrorMessage, "Ok" ); return 1; } save_mine_data(SaveFile); //==================== CLOSE THE FILE ============================= PHYSFS_close(SaveFile); return 0; } // ----------------------------------------------------------------------------- // saves to an already-open file int save_mine_data(PHYSFS_file * SaveFile) { int header_offset, editor_offset, vertex_offset, segment_offset, texture_offset, walls_offset, triggers_offset; //, links_offset; int newseg_verts_offset; int newsegment_offset; int i; med_compress_mine(); warn_if_concave_segments(); for (i=0;i>nbits); if( int_value > 0x7fff ) { short_value = 0x7fff; } else if( int_value < -0x7fff ) { short_value = -0x7fff; } else short_value = (short)int_value; PHYSFS_writeSLE16(SaveFile, short_value); } //version of dump for unsigned values void dump_fix_as_ushort( fix value, int nbits, PHYSFS_file *SaveFile ) { uint int_value=0; ushort short_value; if (value < 0) { Int3(); //hey---show this to Matt value = 0; } else int_value = value >> nbits; if( int_value > 0xffff ) { short_value = 0xffff; } else short_value = int_value; PHYSFS_writeULE16(SaveFile, short_value); } void write_children(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile) { int bit; for (bit = 0; bit < MAX_SIDES_PER_SEGMENT; bit++) { if (bit_mask & (1 << bit)) PHYSFS_writeSLE16(SaveFile, seg->children[bit]); } } void write_verts(segment *seg, PHYSFS_file *SaveFile) { int i; for (i = 0; i < MAX_VERTICES_PER_SEGMENT; i++) PHYSFS_writeSLE16(SaveFile, seg->verts[i]); } void write_special(segment *seg, ubyte bit_mask, PHYSFS_file *SaveFile) { if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT)) { PHYSFSX_writeU8(SaveFile, seg->special); PHYSFSX_writeU8(SaveFile, seg->matcen_num); PHYSFS_writeSLE16(SaveFile, seg->value); } } // ----------------------------------------------------------------------------- // saves compiled mine data to an already-open file... int save_mine_data_compiled(PHYSFS_file *SaveFile) { short i, segnum, sidenum; ubyte version = COMPILED_MINE_VERSION; ubyte bit_mask = 0; med_compress_mine(); warn_if_concave_segments(); if (Highest_segment_index >= MAX_SEGMENTS) { char message[128]; sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_SEGMENTS); ui_messagebox( -2, -2, 1, message, "Ok" ); } if (Highest_vertex_index >= MAX_VERTICES) { char message[128]; sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_VERTICES); ui_messagebox( -2, -2, 1, message, "Ok" ); } //=============================== Writing part ============================== PHYSFSX_writeU8(SaveFile, version); // 1 byte = compiled version if (New_file_format_save) { PHYSFS_writeSLE16(SaveFile, Num_vertices); // 2 bytes = Num_vertices PHYSFS_writeSLE16(SaveFile, Num_segments); // 2 bytes = Num_segments } else { PHYSFS_writeSLE32(SaveFile, Num_vertices); // 4 bytes = Num_vertices PHYSFS_writeSLE32(SaveFile, Num_segments); // 4 bytes = Num_segments } for (i = 0; i < Num_vertices; i++) PHYSFSX_writeVector(SaveFile, &(Vertices[i])); for (segnum = 0; segnum < Num_segments; segnum++) { segment *seg = &Segments[segnum]; for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { if (seg->children[sidenum] != -1) bit_mask |= (1 << sidenum); } if ((seg->special != 0) || (seg->matcen_num != 0) || (seg->value != 0)) bit_mask |= (1 << MAX_SIDES_PER_SEGMENT); if (New_file_format_save) PHYSFSX_writeU8(SaveFile, bit_mask); else bit_mask = 0x7F; if (Gamesave_current_version == 5) // d2 SHAREWARE level { write_special(seg, bit_mask, SaveFile); write_verts(seg, SaveFile); write_children(seg, bit_mask, SaveFile); } else { write_children(seg, bit_mask, SaveFile); write_verts(seg, SaveFile); if (Gamesave_current_version <= 1) // descent 1 level write_special(seg, bit_mask, SaveFile); } if (Gamesave_current_version <= 5) // descent 1 thru d2 SHAREWARE level dump_fix_as_ushort(seg->static_light, 4, SaveFile); // Write the walls as a 6 byte array bit_mask = 0; for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { uint wallnum; if (seg->sides[sidenum].wall_num >= 0) { bit_mask |= (1 << sidenum); wallnum = seg->sides[sidenum].wall_num; Assert( wallnum < 255 ); // Get John or Mike.. can only store up to 255 walls!!! (void)wallnum; } } if (New_file_format_save) PHYSFSX_writeU8(SaveFile, bit_mask); else bit_mask = 0x3F; for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { if (bit_mask & (1 << sidenum)) PHYSFSX_writeU8(SaveFile, seg->sides[sidenum].wall_num); } for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { if ((seg->children[sidenum] == -1) || (seg->sides[sidenum].wall_num != -1)) { ushort tmap_num, tmap_num2; tmap_num = seg->sides[sidenum].tmap_num; tmap_num2 = seg->sides[sidenum].tmap_num2; if (tmap_num2 != 0 && New_file_format_save) tmap_num |= 0x8000; PHYSFS_writeSLE16(SaveFile, tmap_num); if (tmap_num2 != 0 || !New_file_format_save) PHYSFS_writeSLE16(SaveFile, tmap_num2); for (i = 0; i < 4; i++) { dump_fix_as_short(seg->sides[sidenum].uvls[i].u, 5, SaveFile); dump_fix_as_short(seg->sides[sidenum].uvls[i].v, 5, SaveFile); dump_fix_as_ushort(seg->sides[sidenum].uvls[i].l, 1, SaveFile); } } } } #if 0 if (Gamesave_current_version > 5) for (i = 0; i < Num_segments; i++) segment2_write(&Segment2s[i], SaveFile); #endif return 0; } dxx-rebirth-0.58.1-d1x/editor/objpage.c000066400000000000000000000254371217717257200176260ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * object selection stuff. * */ #include #include #include "inferno.h" #include "screens.h" // For GAME_SCREEN????? #include "editor.h" // For TMAP_CURBOX?????? #include "gr.h" // For canves, font stuff #include "ui.h" // For UI_GADGET stuff #include "object.h" // For robot_bms #include "dxxerror.h" #include "objpage.h" #include "bm.h" #include "player.h" #include "piggy.h" #include "cntrlcen.h" #define OBJS_PER_PAGE 8 static UI_GADGET_USERBOX * ObjBox[OBJS_PER_PAGE]; static UI_GADGET_USERBOX * ObjCurrent; static int ObjectPage = 0; #include "vecmat.h" #include "3d.h" #include "polyobj.h" #include "texmap.h" #include "hostage.h" #include "powerup.h" vms_angvec objpage_view_orient; fix objpage_view_dist; //this is bad to have the extern, but this snapshot stuff is special extern int polyobj_lighting; //canvas set void draw_object_picture(int id, vms_angvec *orient_angles, int type) { if (id >= Num_object_subtypes) return; switch (type) { case OBJ_HOSTAGE: PIGGY_PAGE_IN(Vclip[Hostage_vclip_num[id]].frames[0]); gr_bitmap(0,0,&GameBitmaps[Vclip[Hostage_vclip_num[id]].frames[0].index]); break; case OBJ_POWERUP: if ( Powerup_info[id].vclip_num > -1 ) { PIGGY_PAGE_IN(Vclip[Powerup_info[id].vclip_num].frames[0]); gr_bitmap(0,0,&GameBitmaps[Vclip[Powerup_info[id].vclip_num].frames[0].index]); } break; case OBJ_PLAYER: draw_model_picture(Player_ship->model_num,orient_angles); // Draw a poly model below break; case OBJ_ROBOT: draw_model_picture(Robot_info[id].model_num,orient_angles); // Draw a poly model below break; case OBJ_CNTRLCEN: draw_model_picture(get_reactor_model_number(id), orient_angles); break; case OBJ_CLUTTER: draw_model_picture(id, orient_angles); break; default: //Int3(); // Invalid type!!! return; } } void redraw_current_object() { grs_canvas * cc; cc = grd_curcanv; gr_set_current_canvas(ObjCurrent->canvas); draw_object_picture(Cur_object_id, &objpage_view_orient, Cur_object_type); gr_set_current_canvas(cc); } void gr_label_box( int i) { gr_clear_canvas(BM_XRGB(0,0,0)); draw_object_picture(i, &objpage_view_orient, Cur_object_type); // char s[20]; // sprintf( s, " %d ", i ); // gr_clear_canvas( BM_XRGB(0,15,0) ); // gr_set_fontcolor( CWHITE, BM_XRGB(0,15,0) ); // ui_string_centered( grd_curcanv->cv_bitmap.bm_w/2, grd_curcanv->cv_bitmap.bm_h/2, Description[i] ); } int objpage_goto_first() { int i; ObjectPage=0; for (i=0; icanvas); if (i+ObjectPage*OBJS_PER_PAGE < Num_object_subtypes ) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else gr_clear_canvas( CGREY ); } return 1; } int objpage_goto_last() { int i; ObjectPage=(Num_object_subtypes)/OBJS_PER_PAGE; for (i=0; icanvas); if (i+ObjectPage*OBJS_PER_PAGE < Num_object_subtypes ) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else { gr_clear_canvas( CGREY ); } } return 1; } static int objpage_goto_prev() { int i; if (ObjectPage > 0) { ObjectPage--; for (i=0; icanvas); if (i+ObjectPage*OBJS_PER_PAGE < Num_object_subtypes) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else { gr_clear_canvas( CGREY ); } } } return 1; } static int objpage_goto_next() { int i; if ((ObjectPage+1)*OBJS_PER_PAGE < Num_object_subtypes) { ObjectPage++; for (i=0; icanvas); if (i+ObjectPage*OBJS_PER_PAGE < Num_object_subtypes) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else { gr_clear_canvas( CGREY ); } } } return 1; } int objpage_grab_current(int n) { int i; if ((n < 0) || (n >= Num_object_subtypes)) return 0; ObjectPage = n / OBJS_PER_PAGE; if (ObjectPage*OBJS_PER_PAGE < Num_object_subtypes) { for (i=0; icanvas); if (i + ObjectPage*OBJS_PER_PAGE < Num_object_subtypes) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else { gr_clear_canvas( CGREY ); } } } Cur_object_id = n; gr_set_current_canvas(ObjCurrent->canvas); //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ Cur_robot_type ] ] ); gr_label_box(Cur_object_id); //objpage_display_name( Texture[Cur_robot_type]->filename ); return 1; } int objpage_goto_next_object() { // there should be a pop-up menu for this switch (Cur_object_type) { case OBJ_ROBOT: Cur_object_type = OBJ_HOSTAGE; Num_object_subtypes = 1; break; case OBJ_HOSTAGE: Cur_object_type = OBJ_PLAYER; Num_object_subtypes = 1; // can have anarchy/coop, but this is handled automatically break; case OBJ_PLAYER: Cur_object_type = OBJ_POWERUP; Num_object_subtypes = N_powerup_types; break; case OBJ_POWERUP: Cur_object_type = OBJ_CNTRLCEN; Num_object_subtypes = get_num_reactor_models(); break; case OBJ_CNTRLCEN: default: Cur_object_type = OBJ_ROBOT; Num_object_subtypes = N_robot_types; break; } objpage_grab_current(0); return 1; } #define OBJBOX_X (TMAPBOX_X) //location of first one #define OBJBOX_Y (OBJCURBOX_Y - 24 ) #define OBJBOX_W 64 #define OBJBOX_H 64 #define DELTA_ANG 0x800 int objpage_increase_pitch() { objpage_view_orient.p += DELTA_ANG; redraw_current_object(); return 1; } int objpage_decrease_pitch() { objpage_view_orient.p -= DELTA_ANG; redraw_current_object(); return 1; } int objpage_increase_heading() { objpage_view_orient.h += DELTA_ANG; redraw_current_object(); return 1; } int objpage_decrease_heading() { objpage_view_orient.h -= DELTA_ANG; redraw_current_object(); return 1; } int objpage_increase_bank() { objpage_view_orient.b += DELTA_ANG; redraw_current_object(); return 1; } int objpage_decrease_bank() { objpage_view_orient.b -= DELTA_ANG; redraw_current_object(); return 1; } int objpage_increase_z() { objpage_view_dist -= 0x8000; redraw_current_object(); return 1; } int objpage_decrease_z() { objpage_view_dist += 0x8000; redraw_current_object(); return 1; } int objpage_reset_orient() { objpage_view_orient.p = 0; objpage_view_orient.b = 0; objpage_view_orient.h = -0x8000; //objpage_view_dist = DEFAULT_VIEW_DIST; redraw_current_object(); return 1; } // INIT TEXTURE STUFF void objpage_init( UI_DIALOG *dlg ) { int i; //Num_total_object_types = N_polygon_models + N_hostage_types + N_powerup_types; //Assert (N_polygon_models < MAX_POLYGON_MODELS); //Assert (Num_total_object_types < MAX_OBJTYPE ); //Assert (N_hostage_types < MAX_HOSTAGE_TYPES ); //Assert (N_powerup_types < MAX_POWERUP_TYPES ); // Assert (N_robot_types < MAX_ROBOTS); ui_add_gadget_button( dlg, OBJCURBOX_X + 00, OBJCURBOX_Y - 27, 30, 20, "<<", objpage_goto_prev ); ui_add_gadget_button( dlg, OBJCURBOX_X + 32, OBJCURBOX_Y - 27, 30, 20, ">>", objpage_goto_next ); ui_add_gadget_button( dlg, OBJCURBOX_X + 00, OBJCURBOX_Y - 54, 30, 20, "B", objpage_goto_first ); ui_add_gadget_button( dlg, OBJCURBOX_X + 32, OBJCURBOX_Y - 54, 30, 20, "E", objpage_goto_last ); ui_add_gadget_button( dlg, OBJCURBOX_X + 25, OBJCURBOX_Y + 62, 22, 13, "P-", objpage_decrease_pitch ); ui_add_gadget_button( dlg, OBJCURBOX_X + 25, OBJCURBOX_Y + 90, 22, 13, "P+", objpage_increase_pitch ); ui_add_gadget_button( dlg, OBJCURBOX_X + 00, OBJCURBOX_Y + 90, 22, 13, "B-", objpage_decrease_bank ); ui_add_gadget_button( dlg, OBJCURBOX_X + 50, OBJCURBOX_Y + 90, 22, 13, "B+", objpage_increase_bank ); ui_add_gadget_button( dlg, OBJCURBOX_X + 00, OBJCURBOX_Y + 76, 22, 13, "H-", objpage_decrease_heading ); ui_add_gadget_button( dlg, OBJCURBOX_X + 50, OBJCURBOX_Y + 76, 22, 13, "H+", objpage_increase_heading ); ui_add_gadget_button( dlg, OBJCURBOX_X + 00, OBJCURBOX_Y + 62, 22, 13, "Z+", objpage_increase_z ); ui_add_gadget_button( dlg, OBJCURBOX_X + 50, OBJCURBOX_Y + 62, 22, 13, "Z-", objpage_decrease_z ); ui_add_gadget_button( dlg, OBJCURBOX_X + 25, OBJCURBOX_Y + 76, 22, 13, "R", objpage_reset_orient ); for (i=0;itype == EVENT_UI_DIALOG_DRAW) { for (i=0; icanvas); if (i+ObjectPage*OBJS_PER_PAGE < Num_object_subtypes) { //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ i+ObjectPage*OBJS_PER_PAGE ] ] ); gr_label_box(i+ObjectPage*OBJS_PER_PAGE ); } else { gr_clear_canvas( CGREY ); } } // Don't reset robot_type when we return to editor. // Cur_robot_type = ObjectPage*OBJS_PER_PAGE; gr_set_current_canvas(ObjCurrent->canvas); //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ Cur_robot_type ] ] ); gr_label_box(Cur_object_id); //ObjnameCanvas = gr_create_sub_canvas(&grd_curscreen->sc_canvas, OBJCURBOX_X , OBJCURBOX_Y + OBJBOX_H + 10, 100, 20); //gr_set_current_canvas( ObjnameCanvas ); //gr_set_curfont( ui_small_font ); //gr_set_fontcolor( CBLACK, CWHITE ); //objpage_display_name( Texture[Cur_robot_type]->filename ); return 1; } for (i=0; icanvas); //gr_ubitmap(0,0, robot_bms[robot_bm_nums[ Cur_robot_type ] ] ); gr_label_box(Cur_object_id); //objpage_display_name( Texture[Cur_robot_type]->filename ); return 1; } } return 0; } dxx-rebirth-0.58.1-d1x/editor/segment.c000066400000000000000000001671261217717257200176630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Interrogation functions for segment data structure. * */ #include #include #include #include #include "key.h" #include "gr.h" #include "inferno.h" #include "segment.h" #include "editor.h" #include "editor/esegment.h" #include "dxxerror.h" #include "object.h" #include "gameseg.h" #include "render.h" #include "game.h" #include "wall.h" #include "switch.h" #include "fuelcen.h" #include "cntrlcen.h" #include "seguvs.h" #include "gameseq.h" #include "medwall.h" #include "hostage.h" int Do_duplicate_vertex_check = 0; // Gets set to 1 in med_create_duplicate_vertex, means to check for duplicate vertices in compress_mine #define BOTTOM_STUFF 0 // Remap all vertices in polygons in a segment through translation table xlate_verts. #if BOTTOM_STUFF void remap_vertices(segment *segp, int *xlate_verts) { int sidenum, facenum, polynum, v; for (sidenum=0; sidenumsides[sidenum].num_faces; facenum++) for (polynum=0; polynumsides[sidenum].faces[facenum].num_polys; polynum++) { poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum]; for (v=0; vnum_vertices; v++) pp->verts[v] = xlate_verts[pp->verts[v]]; } } // Copy everything from sourceside to destside except sourceside->faces[xx].polys[xx].verts void copy_side_except_vertex_ids(side *destside, side *sourceside) { int facenum, polynum, v; destside->num_faces = sourceside->num_faces; destside->tri_edge = sourceside->tri_edge; destside->wall_num = sourceside->wall_num; for (facenum=0; facenumnum_faces; facenum++) { face *destface = &destside->faces[facenum]; face *sourceface = &sourceside->faces[facenum]; destface->num_polys = sourceface->num_polys; destface->normal = sourceface->normal; for (polynum=0; polynumnum_polys; polynum++) { poly *destpoly = &destface->polys[polynum]; poly *sourcepoly = &sourceface->polys[polynum]; destpoly->num_vertices = sourcepoly->num_vertices; destpoly->face_type = sourcepoly->face_type; destpoly->tmap_num = sourcepoly->tmap_num; destpoly->tmap_num2 = sourcepoly->tmap_num2; for (v=0; vnum_vertices; v++) destpoly->uvls[v] = sourcepoly->uvls[v]; } } } // [side] [index] [cur:next] // To remap the vertices on a side after a forward rotation sbyte xlate_previous[6][4][2] = { { {7, 3}, {3, 2}, {2, 6}, {6, 7} }, // remapping left to left { {5, 4}, {4, 0}, {7, 3}, {6, 7} }, // remapping back to top { {5, 4}, {1, 5}, {0, 1}, {4, 0} }, // remapping right to right { {0, 1}, {1, 5}, {2, 6}, {3, 2} }, // remapping front to bottom { {1, 5}, {5, 4}, {6, 7}, {2, 6} }, // remapping bottom to back { {4, 0}, {0, 1}, {3, 2}, {7, 3} }, // remapping top to front }; void remap_vertices_previous(segment *segp, int sidenum) { int v, w, facenum, polynum; for (facenum=0; facenumsides[sidenum].num_faces; facenum++) { for (polynum=0; polynumsides[sidenum].faces[facenum].num_polys; polynum++) { poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum]; for (v=0; vnum_vertices; v++) { for (w=0; w<4; w++) { if (pp->verts[v] == xlate_previous[sidenum][w][0]) { pp->verts[v] = xlate_previous[sidenum][w][1]; break; } } Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus } } } } sbyte xlate_previous_right[6][4][2] = { { {5, 6}, {6, 7}, {2, 3}, {1, 2} }, // bottom to left { {6, 7}, {7, 4}, {3, 0}, {2, 3} }, // left to top { {7, 4}, {4, 5}, {0, 1}, {3, 0} }, // top to right { {4, 5}, {5, 6}, {1, 2}, {0, 1} }, // right to bottom { {6, 7}, {5, 6}, {4, 5}, {7, 4} }, // back to back { {3, 2}, {0, 3}, {1, 0}, {2, 1} }, // front to front }; void remap_vertices_previous_right(segment *segp, int sidenum) { int v, w, facenum, polynum; for (facenum=0; facenumsides[sidenum].num_faces; facenum++) { for (polynum=0; polynumsides[sidenum].faces[facenum].num_polys; polynum++) { poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum]; for (v=0; vnum_vertices; v++) { for (w=0; w<4; w++) { if (pp->verts[v] == xlate_previous_right[sidenum][w][0]) { pp->verts[v] = xlate_previous_right[sidenum][w][1]; break; } } Assert(w<4); // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus } } } } // ----------------------------------------------------------------------------------- // Takes top to front void med_rotate_segment_forward(segment *segp) { segment seg_copy; int i; seg_copy = *segp; seg_copy.verts[0] = segp->verts[4]; seg_copy.verts[1] = segp->verts[0]; seg_copy.verts[2] = segp->verts[3]; seg_copy.verts[3] = segp->verts[7]; seg_copy.verts[4] = segp->verts[5]; seg_copy.verts[5] = segp->verts[1]; seg_copy.verts[6] = segp->verts[2]; seg_copy.verts[7] = segp->verts[6]; seg_copy.children[WFRONT] = segp->children[WTOP]; seg_copy.children[WTOP] = segp->children[WBACK]; seg_copy.children[WBACK] = segp->children[WBOTTOM]; seg_copy.children[WBOTTOM] = segp->children[WFRONT]; seg_copy.sides[WFRONT] = segp->sides[WTOP]; seg_copy.sides[WTOP] = segp->sides[WBACK]; seg_copy.sides[WBACK] = segp->sides[WBOTTOM]; seg_copy.sides[WBOTTOM] = segp->sides[WFRONT]; for (i=0; i<6; i++) remap_vertices_previous(&seg_copy, i); *segp = seg_copy; } // ----------------------------------------------------------------------------------- // Takes top to right void med_rotate_segment_right(segment *segp) { segment seg_copy; int i; seg_copy = *segp; seg_copy.verts[4] = segp->verts[7]; seg_copy.verts[5] = segp->verts[4]; seg_copy.verts[1] = segp->verts[0]; seg_copy.verts[0] = segp->verts[3]; seg_copy.verts[3] = segp->verts[2]; seg_copy.verts[2] = segp->verts[1]; seg_copy.verts[6] = segp->verts[5]; seg_copy.verts[7] = segp->verts[6]; seg_copy.children[WRIGHT] = segp->children[WTOP]; seg_copy.children[WBOTTOM] = segp->children[WRIGHT]; seg_copy.children[WLEFT] = segp->children[WBOTTOM]; seg_copy.children[WTOP] = segp->children[WLEFT]; seg_copy.sides[WRIGHT] = segp->sides[WTOP]; seg_copy.sides[WBOTTOM] = segp->sides[WRIGHT]; seg_copy.sides[WLEFT] = segp->sides[WBOTTOM]; seg_copy.sides[WTOP] = segp->sides[WLEFT]; for (i=0; i<6; i++) remap_vertices_previous_right(&seg_copy, i); *segp = seg_copy; } void make_curside_bottom_side(void) { switch (Curside) { case WRIGHT: med_rotate_segment_right(Cursegp); break; case WTOP: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break; case WLEFT: med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); med_rotate_segment_right(Cursegp); break; case WBOTTOM: break; case WFRONT: med_rotate_segment_forward(Cursegp); break; case WBACK: med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); med_rotate_segment_forward(Cursegp); break; } Update_flags = UF_WORLD_CHANGED; } #endif int ToggleBottom(void) { Render_only_bottom = !Render_only_bottom; Update_flags = UF_WORLD_CHANGED; return 0; } // --------------------------------------------------------------------------------------------- // ---------- Segment interrogation functions ---------- // ---------------------------------------------------------------------------- // Return a pointer to the list of vertex indices for the current segment in vp and // the number of vertices in *nv. void med_get_vertex_list(segment *s,int *nv,int **vp) { *vp = s->verts; *nv = MAX_VERTICES_PER_SEGMENT; } // ------------------------------------------------------------------------------- // Return number of times vertex vi appears in all segments. // This function can be used to determine whether a vertex is used exactly once in // all segments, in which case it can be freely moved because it is not connected // to any other segment. int med_vertex_count(int vi) { int s,v; segment *sp; int count; count = 0; for (s=0; ssegnum != -1) for (v=0; vverts[v] == vi) count++; } return count; } // ------------------------------------------------------------------------------- int is_free_vertex(int vi) { return med_vertex_count(vi) == 1; } // ------------------------------------------------------------------------------- // Move a free vertex in the segment by adding the vector *vofs to its coordinates. // Error handling: // If the point is not free then: // If the point is not valid (probably valid = in 0..7) then: // If adding *vofs will cause a degenerate segment then: // Note, pi is the point index relative to the segment, not an absolute point index. // For example, 3 is always the front upper left vertex. void med_move_vertex(segment *sp, int pi, vms_vector *vofs) { int abspi; Assert((pi >= 0) && (pi <= 7)); // check valid range of point indices. abspi = sp->verts[pi]; // Make sure vertex abspi is free. If it is free, it appears exactly once in Vertices Assert(med_vertex_count(abspi) == 1); Assert(abspi <= MAX_SEGMENT_VERTICES); // Make sure vertex id is not bogus. vm_vec_add(&Vertices[abspi],&Vertices[abspi],vofs); // Here you need to validate the geometry of the segment, which will be quite tricky. // You need to make sure: // The segment is not concave. // None of the sides are concave. validate_segment(sp); } // ------------------------------------------------------------------------------- // Move a free wall in the segment by adding the vector *vofs to its coordinates. // Wall indices: 0/1/2/3/4/5 = left/top/right/bottom/back/front void med_move_wall(segment *sp,int wi, vms_vector *vofs) { sbyte *vp; int i; Assert( (wi >= 0) && (wi <= 5) ); vp = Side_to_verts[wi]; for (i=0; i<4; i++) { med_move_vertex(sp,*vp,vofs); vp++; } validate_segment(sp); } // ------------------------------------------------------------------------------- // Return true if one fixed point number is very close to another, else return false. int fnear(fix f1, fix f2) { return (abs(f1 - f2) <= FIX_EPSILON); } // ------------------------------------------------------------------------------- int vnear(vms_vector *vp1, vms_vector *vp2) { return fnear(vp1->x, vp2->x) && fnear(vp1->y, vp2->y) && fnear(vp1->z, vp2->z); } // ------------------------------------------------------------------------------- // Add the vertex *vp to the global list of vertices, return its index. // Search until a matching vertex is found (has nearly the same coordinates) or until Num_vertices // vertices have been looked at without a match. If no match, add a new vertex. int med_add_vertex(vms_vector *vp) { int v,free_index; int count; // number of used vertices found, for loops exits when count == Num_vertices // set_vertex_counts(); Assert(Num_vertices < MAX_SEGMENT_VERTICES); count = 0; free_index = -1; for (v=0; (v < MAX_SEGMENT_VERTICES) && (count < Num_vertices); v++) if (Vertex_active[v]) { count++; if (vnear(vp,&Vertices[v])) { return v; } } else if (free_index == -1) free_index = v; // we want free_index to be the first free slot to add a vertex if (free_index == -1) free_index = Num_vertices; while (Vertex_active[free_index] && (free_index < MAX_VERTICES)) free_index++; Assert(free_index < MAX_VERTICES); Vertices[free_index] = *vp; Vertex_active[free_index] = 1; Num_vertices++; if (free_index > Highest_vertex_index) Highest_vertex_index = free_index; return free_index; } // ------------------------------------------------------------------------------------------ // Returns the index of a free segment. // Scans the Segments array. int get_free_segment_number(void) { int segnum; for (segnum=0; segnum Highest_segment_index) Highest_segment_index = segnum; return segnum; } Assert(0); return 0; } // ------------------------------------------------------------------------------- // Create a new segment, duplicating exactly, including vertex ids and children, the passed segment. int med_create_duplicate_segment(segment *sp) { int segnum; segnum = get_free_segment_number(); Segments[segnum] = *sp; return segnum; } // ------------------------------------------------------------------------------- // Add the vertex *vp to the global list of vertices, return its index. // This is the same as med_add_vertex, except that it does not search for the presence of the vertex. int med_create_duplicate_vertex(vms_vector *vp) { int free_index; Assert(Num_vertices < MAX_SEGMENT_VERTICES); Do_duplicate_vertex_check = 1; free_index = Num_vertices; while (Vertex_active[free_index] && (free_index < MAX_VERTICES)) free_index++; Assert(free_index < MAX_VERTICES); Vertices[free_index] = *vp; Vertex_active[free_index] = 1; Num_vertices++; if (free_index > Highest_vertex_index) Highest_vertex_index = free_index; return free_index; } // ------------------------------------------------------------------------------- // Set the vertex *vp at index vnum in the global list of vertices, return its index (just for compatibility). int med_set_vertex(int vnum,vms_vector *vp) { Assert(vnum < MAX_VERTICES); Vertices[vnum] = *vp; // Just in case this vertex wasn't active, mark it as active. if (!Vertex_active[vnum]) { Vertex_active[vnum] = 1; Num_vertices++; if ((vnum > Highest_vertex_index) && (vnum < NEW_SEGMENT_VERTICES)) { Highest_vertex_index = vnum; } } return vnum; } // ------------------------------------------------------------------------------- void create_removable_wall(segment *sp, int sidenum, int tmap_num) { create_walls_on_side(sp, sidenum); sp->sides[sidenum].tmap_num = tmap_num; assign_default_uvs_to_side(sp, sidenum); assign_light_to_side(sp, sidenum); } #if 0 // --------------------------------------------------------------------------------------------- // Orthogonalize matrix smat, returning result in rmat. // Does not modify smat. // Uses Gram-Schmidt process. // See page 172 of Strang, Gilbert, Linear Algebra and its Applications // Matt -- This routine should be moved to the vector matrix library. // It IS legal for smat == rmat. // We should also have the functions: // mat_a = mat_b * scalar; // we now have mat_a = mat_a * scalar; // mat_a = mat_b + mat_c * scalar; // or maybe not, maybe this is not primitive void make_orthogonal(vms_matrix *rmat,vms_matrix *smat) { vms_matrix tmat; vms_vector tvec1,tvec2; float dot; // Copy source matrix to work area. tmat = *smat; // Normalize the three rows of the matrix tmat. vm_vec_normalize(&tmat.xrow); vm_vec_normalize(&tmat.yrow); vm_vec_normalize(&tmat.zrow); // Now, compute the first vector. // This is very easy -- just copy the (normalized) source vector. rmat->zrow = tmat.zrow; // Now, compute the second vector. // From page 172 of Strang, we use the equation: // b' = b - [transpose(q1) * b] * q1 // where: b = the second row of tmat // q1 = the first row of rmat // b' = the second row of rmat // Compute: transpose(q1) * b dot = vm_vec_dotprod(&rmat->zrow,&tmat.yrow); // Compute: b - dot * q1 rmat->yrow.x = tmat.yrow.x - fixmul(dot,rmat->zrow.x); rmat->yrow.y = tmat.yrow.y - fixmul(dot,rmat->zrow.y); rmat->yrow.z = tmat.yrow.z - fixmul(dot,rmat->zrow.z); // Now, compute the third vector. // From page 173 of Strang, we use the equation: // c' = c - (q1*c)*q1 - (q2*c)*q2 // where: c = the third row of tmat // q1 = the first row of rmat // q2 = the second row of rmat // c' = the third row of rmat // Compute: q1*c dot = vm_vec_dotprod(&rmat->zrow,&tmat.xrow); tvec1.x = fixmul(dot,rmat->zrow.x); tvec1.y = fixmul(dot,rmat->zrow.y); tvec1.z = fixmul(dot,rmat->zrow.z); // Compute: q2*c dot = vm_vec_dotprod(&rmat->yrow,&tmat.xrow); tvec2.x = fixmul(dot,rmat->yrow.x); tvec2.y = fixmul(dot,rmat->yrow.y); tvec2.z = fixmul(dot,rmat->yrow.z); vm_vec_sub(&rmat->xrow,vm_vec_sub(&rmat->xrow,&tmat.xrow,&tvec1),&tvec2); } #endif // ------------------------------------------------------------------------------------------ // Given a segment, extract the rotation matrix which defines it. // Do this by extracting the forward, right, up vectors and then making them orthogonal. // In the process of making the vectors orthogonal, favor them in the order forward, up, right. // This means that the forward vector will remain unchanged. void med_extract_matrix_from_segment(segment *sp,vms_matrix *rotmat) { vms_vector forwardvec,upvec; extract_forward_vector_from_segment(sp,&forwardvec); extract_up_vector_from_segment(sp,&upvec); if (((forwardvec.x == 0) && (forwardvec.y == 0) && (forwardvec.z == 0)) || ((upvec.x == 0) && (upvec.y == 0) && (upvec.z == 0))) { *rotmat = vmd_identity_matrix; return; } vm_vector_2_matrix(rotmat,&forwardvec,&upvec,NULL); #if 0 vms_matrix rm; extract_forward_vector_from_segment(sp,&rm.zrow); extract_right_vector_from_segment(sp,&rm.xrow); extract_up_vector_from_segment(sp,&rm.yrow); vm_vec_normalize(&rm.xrow); vm_vec_normalize(&rm.yrow); vm_vec_normalize(&rm.zrow); make_orthogonal(rotmat,&rm); vm_vec_normalize(&rotmat->xrow); vm_vec_normalize(&rotmat->yrow); vm_vec_normalize(&rotmat->zrow); // *rotmat = rm; // include this line (and remove the call to make_orthogonal) if you don't want the matrix orthogonalized #endif } // ------------------------------------------------------------------------------------------ // Given a rotation matrix *rotmat which describes the orientation of a segment // and a side destside, return the rotation matrix which describes the orientation for the side. void set_matrix_based_on_side(vms_matrix *rotmat,int destside) { vms_angvec rotvec,*tmpvec; vms_matrix r1,rtemp; switch (destside) { case WLEFT: tmpvec=vm_angvec_make(&rotvec,0,0,-16384); vm_angles_2_matrix(&r1,&rotvec); vm_matrix_x_matrix(&rtemp,rotmat,&r1); *rotmat = rtemp; break; case WTOP: tmpvec=vm_angvec_make(&rotvec,-16384,0,0); vm_angles_2_matrix(&r1,&rotvec); vm_matrix_x_matrix(&rtemp,rotmat,&r1); *rotmat = rtemp; break; case WRIGHT: tmpvec=vm_angvec_make(&rotvec,0,0,16384); vm_angles_2_matrix(&r1,&rotvec); vm_matrix_x_matrix(&rtemp,rotmat,&r1); *rotmat = rtemp; break; case WBOTTOM: tmpvec=vm_angvec_make(&rotvec,+16384,-32768,0); // bank was -32768, but I think that was an erroneous compensation vm_angles_2_matrix(&r1,&rotvec); vm_matrix_x_matrix(&rtemp,rotmat,&r1); *rotmat = rtemp; break; case WFRONT: tmpvec=vm_angvec_make(&rotvec,0,0,-32768); vm_angles_2_matrix(&r1,&rotvec); vm_matrix_x_matrix(&rtemp,rotmat,&r1); *rotmat = rtemp; break; case WBACK: break; } (void)tmpvec; } // ------------------------------------------------------------------------------------- void change_vertex_occurrences(int dest, int src) { int g,s,v; // Fix vertices in groups for (g=0;ghole) && (!Vertex_active[vert]); vert--) ; if (vert > hole) { // Ok, hole is the index of a hole, vert is the index of a vertex which follows it. // Copy vert into hole, update pointers to it. Vertices[hole] = Vertices[vert]; change_vertex_occurrences(hole, vert); vert--; } } Highest_vertex_index = Num_vertices-1; } // -------------------------------------------------------------------------------------------------- void compress_segments(void) { int hole,seg; if (Highest_segment_index == Num_segments - 1) return; seg = Highest_segment_index; for (hole=0; hole < seg; hole++) if (Segments[hole].segnum == -1) { // found an unused segment which is a hole if a used segment follows (not necessarily immediately) it. for ( ; (seg>hole) && (Segments[seg].segnum == -1); seg--) ; if (seg > hole) { int f,g,l,s,t,w; segment *sp; int objnum; // Ok, hole is the index of a hole, seg is the index of a segment which follows it. // Copy seg into hole, update pointers to it, update Cursegp, Markedsegp if necessary. Segments[hole] = Segments[seg]; Segments[seg].segnum = -1; if (Cursegp == &Segments[seg]) Cursegp = &Segments[hole]; if (Markedsegp == &Segments[seg]) Markedsegp = &Segments[hole]; // Fix segments in groups for (g=0;gchildren[s])) { segment *csegp; csegp = &Segments[sp->children[s]]; // Find out on what side the segment connection to the former seg is on in *csegp. for (t=0; tchildren[t] == seg) { csegp->children[t] = hole; // It used to be connected to seg, so make it connected to hole } } // end for t } // end if } // end for s //Update object segment pointers for (objnum = sp->objects; objnum != -1; objnum = Objects[objnum].next) { Assert(Objects[objnum].segnum == seg); Objects[objnum].segnum = hole; } seg--; } // end if (seg > hole) } // end if Highest_segment_index = Num_segments-1; med_create_new_segment_from_cursegp(); } // ------------------------------------------------------------------------------- // Combine duplicate vertices. // If two vertices have the same coordinates, within some small tolerance, then assign // the same vertex number to the two vertices, freeing up one of the vertices. void med_combine_duplicate_vertices(sbyte *vlp) { int v,w; for (v=0; vsides[s].tmap_num = sseg->sides[s].tmap_num; dseg->sides[s].tmap_num2 = 0; } } // ------------------------------------------------------------------------------------------ // Attach a segment with a rotated orientation. // Return value: // 0 = successful attach // 1 = No room in Segments[]. // 2 = No room in Vertices[]. // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side // 4 = already a face attached on destseg:destside int med_attach_segment_rotated(segment *destseg, segment *newseg, int destside, int newside,vms_matrix *attmat) { sbyte *dvp; segment *nsp; int side,v; vms_matrix rotmat,rotmat1,rotmat2,rotmat3,rotmat4; vms_vector vr,vc,tvs[4],xlate_vec; int segnum; vms_vector forvec,upvec; // Return if already a face attached on this side. if (IS_CHILD(destseg->children[destside])) return 4; segnum = get_free_segment_number(); forvec = attmat->fvec; upvec = attmat->uvec; // We are pretty confident we can add the segment. nsp = &Segments[segnum]; nsp->segnum = segnum; nsp->objects = -1; nsp->matcen_num = -1; // Copy group value. nsp->group = destseg->group; // Add segment to proper group list. if (nsp->group > -1) add_segment_to_group(nsp-Segments, nsp->group); // Copy the texture map ids. copy_tmap_ids(nsp,newseg); // clear all connections for (side=0; sidechildren[side] = -1; nsp->sides[side].wall_num = -1; } // Form the connection destseg->children[destside] = segnum; // destseg->sides[destside].render_flag = 0; nsp->children[newside] = destseg-Segments; // Copy vertex indices of the four vertices forming the joint dvp = Side_to_verts[destside]; // Set the vertex indices for the four vertices forming the front of the new side for (v=0; v<4; v++) nsp->verts[v] = destseg->verts[(int) dvp[v]]; // The other 4 vertices must be created. // Their coordinates are determined by the 4 welded vertices and the vector from front // to back of the original *newseg. // Do lots of hideous matrix stuff, about 3/4 of which could probably be simplified out. med_extract_matrix_from_segment(destseg,&rotmat); // get orientation matrix for destseg (orthogonal rotation matrix) set_matrix_based_on_side(&rotmat,destside); vm_vector_2_matrix(&rotmat1,&forvec,&upvec,NULL); vm_matrix_x_matrix(&rotmat4,&rotmat,&rotmat1); // this is the desired orientation of the new segment med_extract_matrix_from_segment(newseg,&rotmat3); // this is the current orientation of the new segment vm_transpose_matrix(&rotmat3); // get the inverse of the current orientation matrix vm_matrix_x_matrix(&rotmat2,&rotmat4,&rotmat3); // now rotmat2 takes the current segment to the desired orientation // Warning -- look at this line! vm_transpose_matrix(&rotmat2); // added 12:33 pm, 10/01/93 // Compute and rotate the center point of the attaching face. compute_center_point_on_side(&vc,newseg,newside); vm_vec_rotate(&vr,&vc,&rotmat2); // Now rotate the free vertices in the segment for (v=0; v<4; v++) vm_vec_rotate(&tvs[v],&Vertices[newseg->verts[v+4]],&rotmat2); // Now translate the new segment so that the center point of the attaching faces are the same. compute_center_point_on_side(&vc,destseg,destside); vm_vec_sub(&xlate_vec,&vc,&vr); // Create and add the 4 new vertices. for (v=0; v<4; v++) { vm_vec_add2(&tvs[v],&xlate_vec); nsp->verts[v+4] = med_add_vertex(&tvs[v]); } set_vertex_counts(); // Now all the vertices are in place. Create the faces. validate_segment(nsp); // Say to not render at the joint. // destseg->sides[destside].render_flag = 0; // nsp->sides[newside].render_flag = 0; Cursegp = nsp; return 0; } // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ------------------------------------------------------------------------------------------ void scale_free_vertices(segment *sp,vms_vector *vp,fix scale_factor,int min_side,int max_side) { int i; sbyte *verts; verts = Side_to_verts[min_side]; for (i=0; i<4; i++) if (is_free_vertex(sp->verts[(int) verts[i]])) { Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2; Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2; Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2; } verts = Side_to_verts[max_side]; for (i=0; i<4; i++) if (is_free_vertex(sp->verts[(int) verts[i]])) { Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2; Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2; Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2; } } // ------------------------------------------------------------------------------------------ // Attach side newside of newseg to side destside of destseg. // Copies *newseg into global array Segments, increments Num_segments. // Forms a weld between the two segments by making the new segment fit to the old segment. // Updates number of faces per side if necessitated by new vertex coordinates. // Updates Cursegp. // Return value: // 0 = successful attach // 1 = No room in Segments[]. // 2 = No room in Vertices[]. // 3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side // 4 = already a face attached on side newside int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside) { int rval; segment *ocursegp = Cursegp; vms_angvec tang = {0,0,0}; vms_matrix rotmat; vm_angles_2_matrix(&rotmat,&tang); rval = med_attach_segment_rotated(destseg,newseg,destside,newside,&rotmat); med_propagate_tmaps_to_segments(ocursegp,Cursegp,0); med_propagate_tmaps_to_back_side(Cursegp, Side_opposite[newside],0); copy_uvs_seg_to_seg(&New_segment,Cursegp); return rval; } // ------------------------------------------------------------------------------- // Delete a vertex, sort of. // Decrement the vertex count. If the count goes to 0, then the vertex is free (has been deleted). void delete_vertex(int v) { Assert(v < MAX_VERTICES); // abort if vertex is not in array Vertices Assert(Vertex_active[v] >= 1); // abort if trying to delete a non-existent vertex Vertex_active[v]--; } // ------------------------------------------------------------------------------- // Update Num_vertices. // This routine should be called by anyone who calls delete_vertex. It could be called in delete_vertex, // but then it would be called much more often than necessary, and it is a slow routine. void update_num_vertices(void) { int v; // Now count the number of vertices. Num_vertices = 0; for (v=0; v<=Highest_vertex_index; v++) if (Vertex_active[v]) Num_vertices++; } // ------------------------------------------------------------------------------- // Set Vertex_active to number of occurrences of each vertex. // Set Num_vertices. void set_vertex_counts(void) { int s,v; Num_vertices = 0; for (v=0; v<=Highest_vertex_index; v++) Vertex_active[v] = 0; // Count number of occurrences of each vertex. for (s=0; s<=Highest_segment_index; s++) if (Segments[s].segnum != -1) for (v=0; vverts[v]); update_num_vertices(); } // ------------------------------------------------------------------------------- // Delete segment *sp in Segments array. // Return value: // 0 successfully deleted. // 1 unable to delete. int med_delete_segment(segment *sp) { int s,side,segnum; int objnum; segnum = sp-Segments; // Cannot delete segment if only segment. if (Num_segments == 1) return 1; // Don't try to delete if segment doesn't exist. if (sp->segnum == -1) { return 1; } // Delete its refueling center if it has one fuelcen_delete(sp); delete_vertices_in_segment(sp); Num_segments--; // If deleted segment has walls on any side, wipe out the wall. for (side=0; side < MAX_SIDES_PER_SEGMENT; side++) if (sp->sides[side].wall_num != -1) wall_remove_side(sp, side); // Find out what this segment was connected to and break those connections at the other end. for (side=0; side < MAX_SIDES_PER_SEGMENT; side++) if (IS_CHILD(sp->children[side])) { segment *csp; // the connecting segment int s; csp = &Segments[sp->children[side]]; for (s=0; schildren[s] == segnum) { csp->children[s] = -1; // this is the side of connection, break it validate_segment_side(csp,s); // we have converted a connection to a side so validate the segment med_propagate_tmaps_to_back_side(csp,s,0); } Cursegp = csp; med_create_new_segment_from_cursegp(); copy_uvs_seg_to_seg(&New_segment,Cursegp); } sp->segnum = -1; // Mark segment as inactive. // If deleted segment = marked segment, then say there is no marked segment if (sp == Markedsegp) Markedsegp = 0; // If deleted segment = a Group segment ptr, then wipe it out. for (s=0;sgroup > -1) delete_segment_from_group(sp-Segments, sp->group); // If we deleted something which was not connected to anything, must now select a new current segment. if (Cursegp == sp) for (s=0; sobjects != -1) { for (objnum=sp->objects;objnum!=-1;objnum=Objects[objnum].next) { //if an object is in the seg, delete it //if the object is the player, move to new curseg if (objnum == (ConsoleObject-Objects)) { compute_segment_center(&ConsoleObject->pos,Cursegp); obj_relink(objnum,Cursegp-Segments); } else obj_delete(objnum); } } // Make sure everything deleted ok... Assert( sp->objects==-1 ); // If we are leaving many holes in Segments or Vertices, then compress mine, because it is inefficient to be that way // if ((Highest_segment_index > Num_segments+4) || (Highest_vertex_index > Num_vertices+4*8)) // med_compress_mine(); return 0; } // ------------------------------------------------------------------------------------------ // Copy texture maps from sseg to dseg void copy_tmaps_to_segment(segment *dseg, segment *sseg) { int s; for (s=0; ssides[s].type = sseg->sides[s].type; dseg->sides[s].tmap_num = sseg->sides[s].tmap_num; dseg->sides[s].tmap_num2 = sseg->sides[s].tmap_num2; } } // ------------------------------------------------------------------------------------------ // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively // modifying its four free vertices in the global array Vertices. // It is illegal to rotate a segment which has connectivity != 1. // Pitch, bank, heading are about the point which is the average of the four points // forming the side of connection. // Return value: // 0 = successful rotation // 1 = Connectivity makes rotation illegal (connected to 0 or 2+ segments) // 2 = Rotation causes degeneracy, such as self-intersecting segment. // 3 = Unable to rotate because not connected to exactly 1 segment. int med_rotate_segment(segment *seg, vms_matrix *rotmat) { segment *destseg; int newside=0,destside,s; int count; int back_side,side_tmaps[MAX_SIDES_PER_SEGMENT]; // Find side of attachment count = 0; for (s=0; schildren[s])) { count++; newside = s; } // Return if passed in segment is connected to other than 1 segment. if (count != 1) return 3; destseg = &Segments[seg->children[newside]]; destside = 0; while ((destseg->children[destside] != seg-Segments) && (destside < MAX_SIDES_PER_SEGMENT)) destside++; // Before deleting the segment, copy its texture maps to New_segment copy_tmaps_to_segment(&New_segment,seg); if (Curside == WFRONT) Curside = WBACK; med_attach_segment_rotated(destseg,&New_segment,destside,AttachSide,rotmat); // Save tmap_num on each side to restore after call to med_propagate_tmaps_to_segments and _back_side // which will change the tmap nums. for (s=0; ssides[s].tmap_num; back_side = Side_opposite[find_connect_side(destseg, seg)]; med_propagate_tmaps_to_segments(destseg, seg,0); med_propagate_tmaps_to_back_side(seg, back_side,0); for (s=0; ssides[s].tmap_num = side_tmaps[s]; return 0; } // ---------------------------------------------------------------------------------------- int med_rotate_segment_ang(segment *seg, vms_angvec *ang) { vms_matrix rotmat; return med_rotate_segment(seg,vm_angles_2_matrix(&rotmat,ang)); } // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ---------------------------------------------------------------------------- // Compute the sum of the distances between the four pairs of points. // The connections are: // firstv1 : 0 (firstv1+1)%4 : 1 (firstv1+2)%4 : 2 (firstv1+3)%4 : 3 fix seg_seg_vertex_distsum(segment *seg1, int side1, segment *seg2, int side2, int firstv1) { fix distsum; int secondv; distsum = 0; for (secondv=0; secondv<4; secondv++) { int firstv; firstv = (4-secondv + (3 - firstv1)) % 4; distsum += vm_vec_dist(&Vertices[seg1->verts[Side_to_verts[side1][firstv]]],&Vertices[seg2->verts[Side_to_verts[side2][secondv]]]); } return distsum; } // ---------------------------------------------------------------------------- // Determine how to connect two segments together with the least amount of twisting. // Returns vertex index in 0..3 on first segment. Assumed ordering of vertices // on second segment is 0,1,2,3. // So, if return value is 2, connect 2:0 3:1 0:2 1:3. // Theory: // We select an ordering of vertices for connection. For the first pair of vertices to be connected, // compute the vector. For the three remaining pairs of vertices, compute the vectors from one vertex // to the other. Compute the dot products of these vectors with the original vector. Add them up. // The close we are to 3, the better fit we have. Reason: The largest value for the dot product is // 1.0, and this occurs for a parallel set of vectors. int get_index_of_best_fit(segment *seg1, int side1, segment *seg2, int side2) { int firstv; fix min_distance; int best_index=0; min_distance = F1_0*30000; for (firstv=0; firstv<4; firstv++) { fix t; t = seg_seg_vertex_distsum(seg1, side1, seg2, side2, firstv); if (t <= min_distance) { min_distance = t; best_index = firstv; } } return best_index; } #define MAX_VALIDATIONS 50 // ---------------------------------------------------------------------------- // Remap uv coordinates in all sides in segment *sp which have a vertex in vp[4]. // vp contains absolute vertex indices. void remap_side_uvs(segment *sp,int *vp) { int s,i,v; for (s=0; schildren[side1]) || IS_CHILD(seg2->children[side2])) return 2; // Make sure there is no wall there if ((seg1->sides[side1].wall_num != -1) || (seg2->sides[side2].wall_num != -1)) return 2; // We can form the joint. Find the best orientation of vertices. bfi = get_index_of_best_fit(seg1, side1, seg2, side2); vp1 = Side_to_verts[side1]; vp2 = Side_to_verts[side2]; // Make a copy of the list of vertices in seg2 which will be deleted and set the // associated vertex number, so that all occurrences of the vertices can be replaced. for (v=0; v<4; v++) lost_vertices[v] = seg2->verts[(int) vp2[v]]; // Now, for each vertex in lost_vertices, determine which vertex it maps to. for (v=0; v<4; v++) remap_vertices[3 - ((v + bfi) % 4)] = seg1->verts[(int) vp1[v]]; // Now, in all segments, replace all occurrences of vertices in lost_vertices with remap_vertices // Put the one segment we know are being modified into the validation list. // Note: seg1 does not require a full validation, only a validation of the affected side. Its vertices do not move. nv = 1; validation_list[0] = seg2 - Segments; for (v=0; v<4; v++) for (s=0; s<=Highest_segment_index; s++) if (Segments[s].segnum != -1) for (sv=0; svchildren[side1] = seg2 - Segments; seg2->children[side2] = seg1 - Segments; // validate all segments validate_segment_side(seg1,side1); for (s=0; schildren[side] != -1) // then it is not legal to form the brider. // Return: // 0 bridge segment formed // 1 unable to form bridge because one (or both) of the sides is not open. // Note that no new vertices are created by this process. int med_form_bridge_segment(segment *seg1, int side1, segment *seg2, int side2) { segment *bs; sbyte *sv; int v,bfi,i; if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2])) return 1; bs = &Segments[get_free_segment_number()]; bs->segnum = bs-Segments; bs->objects = -1; // Copy vertices from seg2 into last 4 vertices of bridge segment. sv = Side_to_verts[side2]; for (v=0; v<4; v++) bs->verts[(3-v)+4] = seg2->verts[(int) sv[v]]; // Copy vertices from seg1 into first 4 vertices of bridge segment. bfi = get_index_of_best_fit(seg1, side1, seg2, side2); sv = Side_to_verts[side1]; for (v=0; v<4; v++) bs->verts[(v + bfi) % 4] = seg1->verts[(int) sv[v]]; // Form connections to children, first initialize all to unconnected. for (i=0; ichildren[i] = -1; bs->sides[i].wall_num = -1; } // Now form connections between segments. bs->children[AttachSide] = seg1 - Segments; bs->children[(int) Side_opposite[AttachSide]] = seg2 - Segments; seg1->children[side1] = bs-Segments; //seg2 - Segments; seg2->children[side2] = bs-Segments; //seg1 - Segments; // Validate bridge segment, and if degenerate, clean up mess. Degenerate_segment_found = 0; validate_segment(bs); if (Degenerate_segment_found) { seg1->children[side1] = -1; seg2->children[side2] = -1; bs->children[AttachSide] = -1; bs->children[(int) Side_opposite[AttachSide]] = -1; if (med_delete_segment(bs)) { Int3(); } editor_status("Bridge segment would be degenerate, not created.\n"); return 1; } else { validate_segment(seg1); // used to only validate side, but segment does more error checking: ,side1); validate_segment(seg2); // ,side2); med_propagate_tmaps_to_segments(seg1,bs,0); editor_status("Bridge segment formed."); warn_if_concave_segment(bs); return 0; } } // ------------------------------------------------------------------------------- // Create a segment given center, dimensions, rotation matrix. // Note that the created segment will always have planar sides and rectangular cross sections. // It will be created with walls on all sides, ie not connected to anything. void med_create_segment(segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp) { int i,f; vms_vector v0,v1,cv; Num_segments++; sp->segnum = 1; // What to put here? I don't know. // Form connections to children, of which it has none. for (i=0; ichildren[i] = -1; // sp->sides[i].render_flag = 0; sp->sides[i].wall_num = -1; } sp->group = -1; sp->matcen_num = -1; // Create relative-to-center vertices, which are the rotated points on the box defined by length, width, height sp->verts[0] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,-length/2),mp)); sp->verts[1] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,-length/2),mp)); sp->verts[2] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,-length/2),mp)); sp->verts[3] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,-length/2),mp)); sp->verts[4] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,+length/2),mp)); sp->verts[5] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,+length/2),mp)); sp->verts[6] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,+length/2),mp)); sp->verts[7] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,+length/2),mp)); // Now create the vector which is the center of the segment and add that to all vertices. while (!vm_vec_make(&cv,cx,cy,cz)); // Now, add the center to all vertices, placing the segment in 3 space. for (i=0; iverts[i]],&Vertices[sp->verts[i]],&cv); // Set scale vector. // sp->scale.x = width; // sp->scale.y = height; // sp->scale.z = length; // Add faces to all sides. for (f=0; fobjects = -1; //no objects in this segment // Assume nothing special about this segment sp->special = 0; sp->value = 0; sp->static_light = 0; sp->matcen_num = -1; copy_tmaps_to_segment(sp, &New_segment); assign_default_uvs_to_segment(sp); } // ---------------------------------------------------------------------------------------------- // Create New_segment using a specified scale factor. void med_create_new_segment(vms_vector *scale) { int s,t; vms_vector v0; segment *sp = &New_segment; fix length,width,height; length = scale->z; width = scale->x; height = scale->y; sp->segnum = 1; // What to put here? I don't know. // Create relative-to-center vertices, which are the points on the box defined by length, width, height t = Num_vertices; sp->verts[0] = med_set_vertex(NEW_SEGMENT_VERTICES+0,vm_vec_make(&v0,+width/2,+height/2,-length/2)); sp->verts[1] = med_set_vertex(NEW_SEGMENT_VERTICES+1,vm_vec_make(&v0,+width/2,-height/2,-length/2)); sp->verts[2] = med_set_vertex(NEW_SEGMENT_VERTICES+2,vm_vec_make(&v0,-width/2,-height/2,-length/2)); sp->verts[3] = med_set_vertex(NEW_SEGMENT_VERTICES+3,vm_vec_make(&v0,-width/2,+height/2,-length/2)); sp->verts[4] = med_set_vertex(NEW_SEGMENT_VERTICES+4,vm_vec_make(&v0,+width/2,+height/2,+length/2)); sp->verts[5] = med_set_vertex(NEW_SEGMENT_VERTICES+5,vm_vec_make(&v0,+width/2,-height/2,+length/2)); sp->verts[6] = med_set_vertex(NEW_SEGMENT_VERTICES+6,vm_vec_make(&v0,-width/2,-height/2,+length/2)); sp->verts[7] = med_set_vertex(NEW_SEGMENT_VERTICES+7,vm_vec_make(&v0,-width/2,+height/2,+length/2)); Num_vertices = t; // sp->scale = *scale; // Form connections to children, of which it has none, init faces and tmaps. for (s=0; schildren[s] = -1; // sp->sides[s].render_flag = 0; sp->sides[s].wall_num = -1; create_walls_on_side(sp,s); sp->sides[s].tmap_num = s; // assign some stupid old tmap to this side. sp->sides[s].tmap_num2 = 0; } Seg_orientation.p = 0; Seg_orientation.b = 0; Seg_orientation.h = 0; sp->objects = -1; //no objects in this segment assign_default_uvs_to_segment(sp); // Assume nothing special about this segment sp->special = 0; sp->value = 0; sp->static_light = 0; sp->matcen_num = -1; } // ------------------------------------------------------------------------------- void med_create_new_segment_from_cursegp(void) { vms_vector scalevec; vms_vector uvec, rvec, fvec; med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec); med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec); extract_forward_vector_from_segment(Cursegp, &fvec); scalevec.x = vm_vec_mag(&rvec); scalevec.y = vm_vec_mag(&uvec); scalevec.z = vm_vec_mag(&fvec); med_create_new_segment(&scalevec); } // ------------------------------------------------------------------------------- // Initialize all vertices to inactive status. void init_all_vertices(void) { int v; int s; for (v=0; vverts[v]; // Now copy the whole struct. *dsp = *ssp; // Now restore the vertex indices. for (v=0; vverts[v] = verts_copy[v]; // Now destructively modify the vertex values for all vertex indices. for (v=0; vverts[v]] = Vertices[ssp->verts[v]]; } // ----------------------------------------------------------------------------- // Create coordinate axes in orientation of specified segment, stores vertices at *vp. void create_coordinate_axes_from_segment(segment *sp,int *vertnums) { vms_matrix rotmat; vms_vector t; med_extract_matrix_from_segment(sp,&rotmat); compute_segment_center(&Vertices[vertnums[0]],sp); t = rotmat.rvec; vm_vec_scale(&t,i2f(32)); vm_vec_add(&Vertices[vertnums[1]],&Vertices[vertnums[0]],&t); t = rotmat.uvec; vm_vec_scale(&t,i2f(32)); vm_vec_add(&Vertices[vertnums[2]],&Vertices[vertnums[0]],&t); t = rotmat.fvec; vm_vec_scale(&t,i2f(32)); vm_vec_add(&Vertices[vertnums[3]],&Vertices[vertnums[0]],&t); } // ----------------------------------------------------------------------------- // Determine if a segment is concave. Returns true if concave int check_seg_concavity(segment *s) { int sn,vn; vms_vector n0,n1; for (sn=0;snverts[Side_to_verts[sn][vn%4]]], &Vertices[s->verts[Side_to_verts[sn][(vn+1)%4]]], &Vertices[s->verts[Side_to_verts[sn][(vn+2)%4]]]); //vm_vec_normalize(&n1); if (vn>0) if (vm_vec_dotprod(&n0,&n1) < f0_5) return 1; n0 = n1; } return 0; } // ----------------------------------------------------------------------------- // Find all concave segments and add to list void find_concave_segs() { int i; segment *s; N_warning_segs = 0; for (s=Segments,i=Highest_segment_index;i>=0;s++,i--) if (s->segnum != -1) if (check_seg_concavity(s)) Warning_segs[N_warning_segs++]=SEG_PTR_2_NUM(s); } // ----------------------------------------------------------------------------- void warn_if_concave_segments(void) { char temp[1]; find_concave_segs(); if (N_warning_segs) { editor_status_fmt("*** WARNING *** %d concave segments in mine! *** WARNING ***",N_warning_segs); sprintf( temp, "%d", N_warning_segs ); } } // ----------------------------------------------------------------------------- // Check segment s, if concave, warn void warn_if_concave_segment(segment *s) { char temp[1]; int result; result = check_seg_concavity(s); if (result) { Warning_segs[N_warning_segs++] = s-Segments; if (N_warning_segs) { editor_status("*** WARNING *** New segment is concave! *** WARNING ***"); sprintf( temp, "%d", N_warning_segs ); } //else // editor_status(""); } //else //editor_status(""); } // ------------------------------------------------------------------------------- // Find segment adjacent to sp:side. // Adjacent means a segment which shares all four vertices. // Return true if segment found and fill in segment in adj_sp and side in adj_side. // Return false if unable to find, in which case adj_sp and adj_side are undefined. int med_find_adjacent_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side) { int seg,s,v,vv; int abs_verts[4]; // Stuff abs_verts[4] array with absolute vertex indices for (v=0; v<4; v++) abs_verts[v] = sp->verts[Side_to_verts[side][v]]; // Scan all segments, looking for a segment which contains the four abs_verts for (seg=0; seg<=Highest_segment_index; seg++) { if (seg != sp-Segments) { for (v=0; v<4; v++) { // do for each vertex in abs_verts for (vv=0; vvchildren[side])) return 0; compute_center_point_on_side(&vsc, sp, side); closest_seg_dist = JOINT_THRESHOLD; // Scan all segments, looking for a segment which contains the four abs_verts for (seg=0; seg<=Highest_segment_index; seg++) if (seg != sp-Segments) for (s=0;ssegnum != -1) for (v=0; vverts[v] <= Highest_vertex_index); } } // ----------------------------------------------------------------------------------------------------- void check_for_overlapping_segment(int segnum) { int i, v; segmasks masks; vms_vector segcenter; compute_segment_center(&segcenter, &Segments[segnum]); for (i=0;i<=Highest_segment_index; i++) { if (i != segnum) { masks = get_seg_masks(&segcenter, i, 0, __FILE__, __LINE__); if (masks.centermask == 0) { continue; } for (v=0; v<8; v++) { vms_vector pdel, presult; vm_vec_sub(&pdel, &Vertices[Segments[segnum].verts[v]], &segcenter); vm_vec_scale_add(&presult, &segcenter, &pdel, (F1_0*15)/16); masks = get_seg_masks(&presult, i, 0, __FILE__, __LINE__); if (masks.centermask == 0) { break; } } } } } // ----------------------------------------------------------------------------------------------------- // Check for overlapping segments. void check_for_overlapping_segments(void) { int i; med_compress_mine(); for (i=0; i<=Highest_segment_index; i++) { check_for_overlapping_segment(i); } } dxx-rebirth-0.58.1-d1x/editor/seguvs.c000066400000000000000000001415101217717257200175220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * u,v coordinate computation for segment faces * */ #include #include #include #include #include #include "inferno.h" #include "segment.h" #include "editor/editor.h" #include "editor/esegment.h" #include "gameseg.h" #include "fix.h" #include "dxxerror.h" #include "wall.h" #include "editor/kdefs.h" #include "bm.h" // Needed for TmapInfo #include "effects.h" // Needed for effects_bm_num #include "fvi.h" void cast_all_light_in_mine(int quick_flag); //--rotate_uvs-- vms_vector Rightvec; // --------------------------------------------------------------------------------------------- // Returns approximate area of a side fix area_on_side(side *sidep) { fix du,dv,width,height; du = sidep->uvls[1].u - sidep->uvls[0].u; dv = sidep->uvls[1].v - sidep->uvls[0].v; width = fix_sqrt(fixmul(du,du) + fixmul(dv,dv)); du = sidep->uvls[3].u - sidep->uvls[0].u; dv = sidep->uvls[3].v - sidep->uvls[0].v; height = fix_sqrt(fixmul(du,du) + fixmul(dv,dv)); return fixmul(width, height); } // ------------------------------------------------------------------------------------------- // DEBUG function -- callable from debugger. // Returns approximate area of all sides which get mapped (ie, are not a connection). // I wrote this because I was curious how much memory would be required to texture map all // sides individually with custom artwork. For demo1.min on 2/18/94, it would be about 5 meg. int area_on_all_sides(void) { int i,s; int total_area = 0; for (i=0; i<=Highest_segment_index; i++) { segment *segp = &Segments[i]; for (s=0; schildren[s])) total_area += f2i(area_on_side(&segp->sides[s])); } return total_area; } fix average_connectivity(void) { int i,s; int total_sides = 0, total_mapped_sides = 0; for (i=0; i<=Highest_segment_index; i++) { segment *segp = &Segments[i]; for (s=0; schildren[s])) total_mapped_sides++; total_sides++; } } return 6 * fixdiv(total_mapped_sides, total_sides); } #define MAX_LIGHT_SEGS 16 // --------------------------------------------------------------------------------------------- // Scan all polys in all segments, return average light value for vnum. // segs = output array for segments containing vertex, terminated by -1. fix get_average_light_at_vertex(int vnum, short *segs) { int segnum, relvnum, sidenum; fix total_light; int num_occurrences; // #ifndef NDEBUG //Removed this ifdef because the version of Assert that I used to get it to compile doesn't work without this symbol. -KRB short *original_segs; original_segs = segs; // #endif num_occurrences = 0; total_light = 0; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; int *vp = segp->verts; for (relvnum=0; relvnumchildren[sidenum])) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) { total_light += sidep->uvls[v].l; num_occurrences++; } } // end if } // end sidenum } } // end segnum *segs = -1; if (num_occurrences) return total_light/num_occurrences; else return 0; } void set_average_light_at_vertex(int vnum) { int relvnum, sidenum; short Segment_indices[MAX_LIGHT_SEGS]; int segind; fix average_light; average_light = get_average_light_at_vertex(vnum, Segment_indices); if (!average_light) return; segind = 0; while (Segment_indices[segind] != -1) { int segnum = Segment_indices[segind++]; segment *segp = &Segments[segnum]; for (relvnum=0; relvnumverts[relvnum] == vnum) break; if (relvnum < MAX_VERTICES_PER_SEGMENT) { for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { if (!IS_CHILD(segp->children[sidenum])) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) sidep->uvls[v].l = average_light; } // end if } // end sidenum } // end if } // end while Update_flags |= UF_WORLD_CHANGED; } void set_average_light_on_side(segment *segp, int sidenum) { int v; if (!IS_CHILD(segp->children[sidenum])) for (v=0; v<4; v++) { set_average_light_at_vertex(segp->verts[Side_to_verts[sidenum][v]]); } } int set_average_light_on_curside(void) { set_average_light_on_side(Cursegp, Curside); return 0; } // ----------------------------------------------------------------------------------------- void set_average_light_on_all_fast(void) { int s,v,relvnum; fix al; int alc; int seglist[MAX_LIGHT_SEGS]; int *segptr; set_vertex_counts(); // Set total light value for all vertices in array average_light. for (v=0; v<=Highest_vertex_index; v++) { al = 0; alc = 0; if (Vertex_active[v]) { segptr = seglist; for (s=0; s<=Highest_segment_index; s++) { segment *segp = &Segments[s]; for (relvnum=0; relvnumverts[relvnum] == v) break; if (relvnum != MAX_VERTICES_PER_SEGMENT) { int si; *segptr++ = s; // Note this segment in list, so we can process it below. Assert(segptr - seglist < MAX_LIGHT_SEGS); for (si=0; sichildren[si])) { side *sidep = &segp->sides[si]; sbyte *vp = Side_to_verts[si]; int vv; for (vv=0; vv<4; vv++) if (*vp++ == relvnum) { al += sidep->uvls[vv].l; alc++; } } // if (segp->children[si == -1) { } // for (si=0... } // if (relvnum != ... } // for (s=0; ... *segptr = -1; // Now, divide average_light by number of number of occurrences for each vertex if (alc) al /= alc; else al = 0; segptr = seglist; while (*segptr != -1) { int segnum = *segptr++; segment *segp = &Segments[segnum]; int sidenum; for (relvnum=0; relvnumverts[relvnum] == v) break; Assert(relvnum < MAX_VERTICES_PER_SEGMENT); // IMPOSSIBLE! This segment is in seglist, but vertex v does not occur! for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { int wid_result; wid_result = WALL_IS_DOORWAY(segp, sidenum); if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) sidep->uvls[v].l = al; } // end if } // end sidenum } // end while } // if (Vertex_active[v]... } // for (v=0... } extern int Doing_lighting_hack_flag; int set_average_light_on_all(void) { // set_average_light_on_all_fast(); Doing_lighting_hack_flag = 1; cast_all_light_in_mine(0); Doing_lighting_hack_flag = 0; Update_flags |= UF_WORLD_CHANGED; // int seg, side; // for (seg=0; seg<=Highest_segment_index; seg++) // for (side=0; sideu; v0.y = 0; v0.z = uv0->v; v1.x = uv1->u; v1.y = 0; v1.z = uv1->v; return vm_vec_dist(&v0,&v1); } // --------------------------------------------------------------------------------------------- // Given a polygon, compress the uv coordinates so that they are as close to 0 as possible. // Do this by adding a constant u and v to each uv pair. void compress_uv_coordinates(side *sidep) { int v; fix uc, vc; uc = 0; vc = 0; for (v=0; v<4; v++) { uc += sidep->uvls[v].u; vc += sidep->uvls[v].v; } uc /= 4; vc /= 4; uc = uc & 0xffff0000; vc = vc & 0xffff0000; for (v=0; v<4; v++) { sidep->uvls[v].u -= uc; sidep->uvls[v].v -= vc; } } // --------------------------------------------------------------------------------------------- void compress_uv_coordinates_on_side(side *sidep) { compress_uv_coordinates(sidep); } // --------------------------------------------------------------------------------------------- void validate_uv_coordinates_on_side(segment *segp, int sidenum) { // int v; // fix uv_dist,threed_dist; // vms_vector tvec; // fix dist_ratios[MAX_VERTICES_PER_POLY]; side *sidep = &segp->sides[sidenum]; // sbyte *vp = Side_to_verts[sidenum]; // This next hunk doesn't seem to affect anything. @mk, 02/13/94 // for (v=1; v<4; v++) { // uv_dist = compute_uv_dist(&sidep->uvls[v],&sidep->uvls[0]); // threed_dist = vm_vec_mag(vm_vec_sub(&tvec,&Vertices[segp->verts[vp[v]],&Vertices[vp[0]])); // dist_ratios[v-1] = fixdiv(uv_dist,threed_dist); // } compress_uv_coordinates_on_side(sidep); } void compress_uv_coordinates_in_segment(segment *segp) { int side; for (side=0; sidesides[side]); } void compress_uv_coordinates_all(void) { int seg; for (seg=0; seg<=Highest_segment_index; seg++) if (Segments[seg].segnum != -1) compress_uv_coordinates_in_segment(&Segments[seg]); } void check_lighting_side(segment *sp, int sidenum) { int v; side *sidep = &sp->sides[sidenum]; for (v=0; v<4; v++) if ((sidep->uvls[v].l > F1_0*16) || (sidep->uvls[v].l < 0)) Int3(); } void check_lighting_segment(segment *segp) { int side; for (side=0; sidesides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v].l = DEFAULT_LIGHTING; } void assign_default_lighting(segment *segp) { int sidenum; for (sidenum=0; sidenumsides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v] = uvls[v]; } #ifdef __WATCOMC__ fix zhypot(fix a,fix b); #pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \ "imul eax" \ "xchg eax,ebx" \ "mov ecx,edx" \ "imul eax" \ "add eax,ebx" \ "adc edx,ecx" \ "call quad_sqrt"; #else fix zhypot(fix a,fix b) { double x = (double)a / 65536; double y = (double)b / 65536; return (long)(sqrt(x * x + y * y) * 65536); } #endif // --------------------------------------------------------------------------------------------- // Assign lighting value to side, a function of the normal vector. void assign_light_to_side(segment *sp, int sidenum) { int v; side *sidep = &sp->sides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v].l = DEFAULT_LIGHTING; } fix Stretch_scale_x = F1_0; fix Stretch_scale_y = F1_0; // --------------------------------------------------------------------------------------------- // Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side. // (Actually, assign them to the coordinates in the faces.) // va, vb = face-relative vertex indices corresponding to uva, uvb. Ie, they are always in 0..3 and should be looked up in // Side_to_verts[side] to get the segment relative index. void assign_uvs_to_side(segment *segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb) { int vlo,vhi,v0,v1,v2,v3; vms_vector fvec,rvec,tvec; vms_matrix rotmat; uvl uvls[4],ruvmag,fuvmag,uvlo,uvhi; fix fmag,mag01; sbyte *vp; Assert( (va<4) && (vb<4) ); Assert((abs(va - vb) == 1) || (abs(va - vb) == 3)); // make sure the verticies specify an edge vp = (sbyte *)&Side_to_verts[sidenum]; // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0 if (va == ((vb + 1) % 4)) { // va = vb + 1 vlo = vb; vhi = va; uvlo = *uvb; uvhi = *uva; } else { vlo = va; vhi = vb; uvlo = *uva; uvhi = *uvb; } Assert(((vlo+1) % 4) == vhi); // If we are on an edge, then uvhi is one more than uvlo (mod 4) uvls[vlo] = uvlo; uvls[vhi] = uvhi; // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4) // Assign u,v scale to a unit length right vector. fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u); if (fmag < 64) { // this is a fix, so 64 = 1/1024 ruvmag.u = F1_0*256; ruvmag.v = F1_0*256; fuvmag.u = F1_0*256; fuvmag.v = F1_0*256; } else { ruvmag.u = uvhi.v - uvlo.v; ruvmag.v = uvlo.u - uvhi.u; fuvmag.u = uvhi.u - uvlo.u; fuvmag.v = uvhi.v - uvlo.v; } v0 = segp->verts[vp[vlo]]; v1 = segp->verts[vp[vhi]]; v2 = segp->verts[vp[(vhi+1)%4]]; v3 = segp->verts[vp[(vhi+2)%4]]; // Compute right vector by computing orientation matrix from: // forward vector = vlo:vhi // right vector = vlo:(vhi+2) % 4 vm_vec_sub(&fvec,&Vertices[v1],&Vertices[v0]); vm_vec_sub(&rvec,&Vertices[v3],&Vertices[v0]); if (((fvec.x == 0) && (fvec.y == 0) && (fvec.z == 0)) || ((rvec.x == 0) && (rvec.y == 0) && (rvec.z == 0))) { rotmat = vmd_identity_matrix; } else vm_vector_2_matrix(&rotmat,&fvec,0,&rvec); rvec = rotmat.rvec; vm_vec_negate(&rvec); fvec = rotmat.fvec; mag01 = vm_vec_dist(&Vertices[v1],&Vertices[v0]); if ((va == 0) || (va == 2)) mag01 = fixmul(mag01, Stretch_scale_x); else mag01 = fixmul(mag01, Stretch_scale_y); if (mag01 < F1_0/1024 ) editor_status_fmt("U, V bogosity in segment #%hu, probably on side #%i. CLEAN UP YOUR MESS!", (unsigned short)(segp-Segments), sidenum); else { vm_vec_sub(&tvec,&Vertices[v2],&Vertices[v1]); uvls[(vhi+1)%4].u = uvhi.u + fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+1)%4].v = uvhi.v + fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01); vm_vec_sub(&tvec,&Vertices[v3],&Vertices[v0]); uvls[(vhi+2)%4].u = uvlo.u + fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+2)%4].v = uvlo.v + fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+1)%4].l = uvhi.l; uvls[(vhi+2)%4].l = uvlo.l; copy_uvs_from_side_to_faces(segp, sidenum, uvls); } } int Vmag = VMAG; // ----------------------------------------------------------------------------------------------------------- // Assign default uvs to side. // This means: // v0 = 0,0 // v1 = k,0 where k is 3d size dependent // v2, v3 assigned by assign_uvs_to_side void assign_default_uvs_to_side(segment *segp,int side) { uvl uv0,uv1; sbyte *vp; uv0.u = 0; uv0.v = 0; vp = Side_to_verts[side]; uv1.u = 0; uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(&Vertices[segp->verts[vp[1]]],&Vertices[segp->verts[vp[0]]])); assign_uvs_to_side(segp, side, &uv0, &uv1, 0, 1); } // ----------------------------------------------------------------------------------------------------------- // Assign default uvs to side. // This means: // v0 = 0,0 // v1 = k,0 where k is 3d size dependent // v2, v3 assigned by assign_uvs_to_side void stretch_uvs_from_curedge(segment *segp, int side) { uvl uv0,uv1; int v0, v1; v0 = Curedge; v1 = (v0 + 1) % 4; uv0.u = segp->sides[side].uvls[v0].u; uv0.v = segp->sides[side].uvls[v0].v; uv1.u = segp->sides[side].uvls[v1].u; uv1.v = segp->sides[side].uvls[v1].v; assign_uvs_to_side(segp, side, &uv0, &uv1, v0, v1); } // -------------------------------------------------------------------------------------------------------------- // Assign default uvs to a segment. void assign_default_uvs_to_segment(segment *segp) { int s; for (s=0; ssides[base_common_side].num_faces; f++) { // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f]; // -- mk021394 -- for (p=0; pnum_polys; p++) { // -- mk021394 -- poly *pp = &fp->polys[p]; // -- mk021394 -- for (v=0; vnum_vertices; v++) // -- mk021394 -- if (pp->verts[v] == v1) { // -- mk021394 -- *ff = f; // -- mk021394 -- *vv = v; // -- mk021394 -- *pi = p; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side // -- mk021394 -- } // -- mk021394 -- // -------------------------------------------------------------------------------------------------------------- // -- mk021394 -- // Find the vertex index in base_seg:base_common_side which is segment relative vertex v1 // -- mk021394 -- // This very specific routine is subsidiary to med_assign_uvs_to_side. // -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv) // -- mk021394 -- { // -- mk021394 -- int p,f,v; // -- mk021394 -- // -- mk021394 -- Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1)); // -- mk021394 -- Assert(base_seg->sides[base_common_side].num_faces <= 2); // -- mk021394 -- // -- mk021394 -- for (f=0; fsides[base_common_side].num_faces; f++) { // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f]; // -- mk021394 -- for (p=0; pnum_polys; p++) { // -- mk021394 -- poly *pp = &fp->polys[p]; // -- mk021394 -- for (v=0; vnum_vertices; v++) // -- mk021394 -- if (pp->verts[v] == v1) { // -- mk021394 -- if (pp->num_vertices == 4) { // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- // -- mk021394 -- if (base_seg->sides[base_common_side].tri_edge == 0) { // triangulated 012, 023, so if f==0, *vv = v, if f==1, *vv = v if v=0, else v+1 // -- mk021394 -- if ((f == 1) && (v > 0)) // -- mk021394 -- v++; // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } else { // triangulated 013, 123 // -- mk021394 -- if (f == 0) { // -- mk021394 -- if (v == 2) // -- mk021394 -- v++; // -- mk021394 -- } else // -- mk021394 -- v++; // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side // -- mk021394 -- } //--rotate_uvs-- // -------------------------------------------------------------------------------------------------------------- //--rotate_uvs-- // Rotate uvl coordinates uva, uvb about their center point by heading //--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec) //--rotate_uvs-- { //--rotate_uvs-- uvl uvc, uva1, uvb1; //--rotate_uvs-- //--rotate_uvs-- uvc.u = (uva->u + uvb->u)/2; //--rotate_uvs-- uvc.v = (uva->v + uvb->v)/2; //--rotate_uvs-- //--rotate_uvs-- uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z); //--rotate_uvs-- uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x); //--rotate_uvs-- //--rotate_uvs-- uva->u = uva1.u + uvc.u; //--rotate_uvs-- uva->v = uva1.v + uvc.v; //--rotate_uvs-- //--rotate_uvs-- uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z); //--rotate_uvs-- uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x); //--rotate_uvs-- //--rotate_uvs-- uvb->u = uvb1.u + uvc.u; //--rotate_uvs-- uvb->v = uvb1.v + uvc.v; //--rotate_uvs-- } // -------------------------------------------------------------------------------------------------------------- void med_assign_uvs_to_side(segment *con_seg, int con_common_side, segment *base_seg, int base_common_side, int abs_id1, int abs_id2) { uvl uv1,uv2; int v,bv1,bv2, vv1, vv2; int cv1=0, cv2=0; bv1 = -1; bv2 = -1; // Find which vertices in segment match abs_id1, abs_id2 for (v=0; vverts[v] == abs_id1) bv1 = v; if (base_seg->verts[v] == abs_id2) bv2 = v; if (con_seg->verts[v] == abs_id1) cv1 = v; if (con_seg->verts[v] == abs_id2) cv2 = v; } // Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2 // cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2 Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1)); // Now, scan 4 vertices in base side and 4 vertices in connected side. // Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2. // Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2 vv1 = -1; vv2 = -1; for (v=0; v<4; v++) { if (bv1 == Side_to_verts[base_common_side][v]) uv1 = base_seg->sides[base_common_side].uvls[v]; if (bv2 == Side_to_verts[base_common_side][v]) uv2 = base_seg->sides[base_common_side].uvls[v]; if (cv1 == Side_to_verts[con_common_side][v]) vv1 = v; if (cv2 == Side_to_verts[con_common_side][v]) vv2 = v; } Assert((uv1.u != uv2.u) || (uv1.v != uv2.v)); Assert( (vv1 != -1) && (vv2 != -1) ); assign_uvs_to_side(con_seg, con_common_side, &uv1, &uv2, vv1, vv2); } // ----------------------------------------------------------------------------- // Given a base and a connecting segment, a side on each of those segments and two global vertex ids, // determine which side in each of the segments shares those two vertices. // This is used to propagate a texture map id to a connecting segment in an expected and desired way. // Since we can attach any side of a segment to any side of another segment, and do so in each case in // four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause // great confusion. void get_side_ids(segment *base_seg, segment *con_seg, int base_side, int con_side, int abs_id1, int abs_id2, int *base_common_side, int *con_common_side) { sbyte *base_vp,*con_vp; int v0,side; *base_common_side = -1; // Find side in base segment which contains the two global vertex ids. for (side=0; sideverts[(int) base_vp[v0]] == abs_id1) && (base_seg->verts[(int) base_vp[(v0+1) % 4]] == abs_id2)) || ((base_seg->verts[(int) base_vp[v0]] == abs_id2) && (base_seg->verts[(int)base_vp[ (v0+1) % 4]] == abs_id1))) { Assert(*base_common_side == -1); // This means two different sides shared the same edge with base_side == impossible! *base_common_side = side; } } } // Note: For connecting segment, process vertices in reversed order. *con_common_side = -1; // Find side in connecting segment which contains the two global vertex ids. for (side=0; sideverts[(int) con_vp[(v0 + 1) % 4]] == abs_id1) && (con_seg->verts[(int) con_vp[v0]] == abs_id2)) || ((con_seg->verts[(int) con_vp[(v0 + 1) % 4]] == abs_id2) && (con_seg->verts[(int) con_vp[v0]] == abs_id1))) { Assert(*con_common_side == -1); // This means two different sides shared the same edge with con_side == impossible! *con_common_side = side; } } } Assert((*base_common_side != -1) && (*con_common_side != -1)); } // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side. // The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides. // If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates // If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates void propagate_tmaps_to_segment_side(segment *base_seg, int base_side, segment *con_seg, int con_side, int abs_id1, int abs_id2, int uv_only_flag) { int base_common_side,con_common_side; int tmap_num; Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1)); // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2 // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2 if (base_seg != con_seg) get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side); else { base_common_side = base_side; con_common_side = con_side; } // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned // to whatever face I find which is on side base_common_side. // First, find tmap_num for base_common_side. If it doesn't exist (ie, there is a connection there), look at the segment // that is connected through it. if (!IS_CHILD(con_seg->children[con_common_side])) { if (!IS_CHILD(base_seg->children[base_common_side])) { // There is at least one face here, so get the tmap_num from there. tmap_num = base_seg->sides[base_common_side].tmap_num; // Now assign all faces in the connecting segment on side con_common_side to tmap_num. if ((uv_only_flag == -1) || (uv_only_flag == 0)) con_seg->sides[con_common_side].tmap_num = tmap_num; if (uv_only_flag != -1) med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2); } else { // There are no faces here, there is a connection, trace through the connection. int cside; cside = find_connect_side(base_seg, &Segments[base_seg->children[base_common_side]]); propagate_tmaps_to_segment_side(&Segments[base_seg->children[base_common_side]], cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag); } } } sbyte Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = { // left top right bottom back front { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} }, // left { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} }, // top { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} }, // right { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} }, // bottom { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} }, // back { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }}; // front // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side // There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching. void med_propagate_tmaps_to_back_side(segment *base_seg, int back_side, int uv_only_flag) { int v1=0,v2=0; int s,ss,tmap_num,back_side_tmap; if (IS_CHILD(base_seg->children[back_side])) return; // connection, so no sides here. // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side] for (s=0; sverts[v1], base_seg->verts[v2], uv_only_flag); // Assign an unused tmap id to the back side. // Note that this can get undone by the caller if this was not part of a new attach, but a rotation or a scale (which // both do attaches). // First see if tmap on back side is anywhere else. if (!uv_only_flag) { back_side_tmap = base_seg->sides[back_side].tmap_num; for (s=0; ssides[s].tmap_num == back_side_tmap) { for (tmap_num=0; tmap_num < MAX_SIDES_PER_SEGMENT; tmap_num++) { for (ss=0; sssides[ss].tmap_num == New_segment.sides[tmap_num].tmap_num) goto found2; // current texture map (tmap_num) is used on current (ss) side, so try next one // Current texture map (tmap_num) has not been used, assign to all faces on back_side. base_seg->sides[back_side].tmap_num = New_segment.sides[tmap_num].tmap_num; goto done1; found2: ; } } } done1: ; } } int fix_bogus_uvs_on_side(void) { med_propagate_tmaps_to_back_side(Cursegp, Curside, 1); return 0; } void fix_bogus_uvs_on_side1(segment *sp, int sidenum, int uvonly_flag) { side *sidep = &sp->sides[sidenum]; if ((sidep->uvls[0].u == 0) && (sidep->uvls[1].u == 0) && (sidep->uvls[2].u == 0)) { med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag); } } void fix_bogus_uvs_seg(segment *segp) { int s; for (s=0; schildren[s])) fix_bogus_uvs_on_side1(segp, s, 1); } } int fix_bogus_uvs_all(void) { int seg; for (seg=0; seg<=Highest_segment_index; seg++) if (Segments[seg].segnum != -1) fix_bogus_uvs_seg(&Segments[seg]); return 0; } // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side // There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching. void med_propagate_tmaps_to_any_side(segment *base_seg, int back_side, int tmap_num, int uv_only_flag) { int v1=0,v2=0; int s; // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side] for (s=0; sverts[v1], base_seg->verts[v2], uv_only_flag); base_seg->sides[back_side].tmap_num = tmap_num; } // ----------------------------------------------------------------------------- // Segment base_seg is connected through side base_side to segment con_seg on con_side. // For all walls in con_seg, find the wall in base_seg which shares an edge. Copy tmap_num // from that side in base_seg to the wall in con_seg. If the wall in base_seg is not present // (ie, there is another segment connected through it), follow the connection through that // segment to get the wall in the connected segment which shares the edge, and get tmap_num from there. void propagate_tmaps_to_segment_sides(segment *base_seg, int base_side, segment *con_seg, int con_side, int uv_only_flag) { sbyte *base_vp; int abs_id1,abs_id2; int v; base_vp = Side_to_verts[base_side]; // Do for each edge on connecting face. for (v=0; v<4; v++) { abs_id1 = base_seg->verts[(int) base_vp[v]]; abs_id2 = base_seg->verts[(int) base_vp[(v+1) % 4]]; propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag); } } // ----------------------------------------------------------------------------- // Propagate texture maps in base_seg to con_seg. // For each wall in con_seg, find the wall in base_seg which shared an edge. Copy tmap_num from that // wall in base_seg to the wall in con_seg. If the wall in base_seg is not present, then look at the // segment connected through base_seg through the wall. The wall with a common edge is the new wall // of interest. Continue searching in this way until a wall of interest is present. void med_propagate_tmaps_to_segments(segment *base_seg,segment *con_seg, int uv_only_flag) { int s; for (s=0; schildren[s] == con_seg-Segments) propagate_tmaps_to_segment_sides(base_seg, s, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag); con_seg->static_light = base_seg->static_light; validate_uv_coordinates(con_seg); } // ------------------------------------------------------------------------------- // Copy texture map uvs from srcseg to destseg. // If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1) // then assign uvs according to side vertex id, not face vertex id. void copy_uvs_seg_to_seg(segment *destseg,segment *srcseg) { int s; for (s=0; ssides[s].tmap_num = srcseg->sides[s].tmap_num; destseg->sides[s].tmap_num2 = srcseg->sides[s].tmap_num2; } destseg->static_light = srcseg->static_light; } // _________________________________________________________________________________________________________________________ // Maximum distance between a segment containing light to a segment to receive light. #define LIGHT_DISTANCE_THRESHOLD (F1_0*80) fix Magical_light_constant = (F1_0*16); // int Seg0, Seg1; //int Bugseg = 27; typedef struct { sbyte flag, hit_type; vms_vector vector; } hash_info; #define FVI_HASH_SIZE 8 #define FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1) // Note: This should be malloced. // Also, the vector should not be 12 bytes, you should only care about some smaller portion of it. hash_info fvi_cache[FVI_HASH_SIZE]; int Hash_hits=0, Hash_retries=0, Hash_calcs=0; // ----------------------------------------------------------------------------------------- // Set light from a light source. // Light incident on a surface is defined by the light incident at its points. // Light at a point = K * (V . N) / d // where: // K = some magical constant to make everything look good // V = normalized vector from light source to point // N = surface normal at point // d = distance from light source to point // (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V) // Light intensity emitted from a light source is defined to be cast from four points. // These four points are 1/64 of the way from the corners of the light source to the center // of its segment. By assuming light is cast from these points, rather than from on the // light surface itself, light will be properly cast on the light surface. Otherwise, the // vector V would be the null vector. // If quick_light set, then don't use find_vector_intersection void cast_light_from_side(segment *segp, int light_side, fix light_intensity, int quick_light) { vms_vector segment_center; int segnum,sidenum,vertnum, lightnum; compute_segment_center(&segment_center, segp); // Do for four lights, one just inside each corner of side containing light. for (lightnum=0; lightnum<4; lightnum++) { int light_vertex_num, i; vms_vector vector_to_center; vms_vector light_location; // fix inverse_segment_magnitude; light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]]; light_location = Vertices[light_vertex_num]; // New way, 5/8/95: Move towards center irrespective of size of segment. vm_vec_sub(&vector_to_center, &segment_center, &light_location); vm_vec_normalize_quick(&vector_to_center); vm_vec_add2(&light_location, &vector_to_center); // -- Old way, before 5/8/95 -- // -- This way was kind of dumb. In larger segments, you move LESS towards the center. // -- Old way, before 5/8/95 -- // Main problem, though, is vertices don't illuminate themselves well in oblong segments because the dot product is small. // -- Old way, before 5/8/95 -- vm_vec_sub(&vector_to_center, &segment_center, &light_location); // -- Old way, before 5/8/95 -- inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center)); // -- Old way, before 5/8/95 -- vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude); for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *rsegp = &Segments[segnum]; vms_vector r_segment_center; fix dist_to_rseg; for (i=0; isides[sidenum]; vms_vector *side_normalp = &rsidep->normals[0]; // kinda stupid? always use vector 0. for (vertnum=0; vertnum<4; vertnum++) { fix distance_to_point, light_at_point, light_dot; vms_vector vert_location, vector_to_light; int abs_vertnum; abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]]; vert_location = Vertices[abs_vertnum]; distance_to_point = vm_vec_dist_quick(&vert_location, &light_location); vm_vec_sub(&vector_to_light, &light_location, &vert_location); vm_vec_normalize(&vector_to_light); // Hack: In oblong segments, it's possible to get a very small dot product // but the light source is very nearby (eg, illuminating light itself!). light_dot = vm_vec_dot(&vector_to_light, side_normalp); if (distance_to_point < F1_0) if (light_dot > 0) light_dot = (light_dot + F1_0)/2; if (light_dot > 0) { light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point); light_at_point = fixmul(light_at_point, Magical_light_constant); if (light_at_point >= 0) { fvi_info hit_data; int hit_type; vms_vector vert_location_1, r_vector_to_center; fix inverse_segment_magnitude; vm_vec_sub(&r_vector_to_center, &r_segment_center, &vert_location); inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(&r_vector_to_center)); vm_vec_scale_add(&vert_location_1, &vert_location, &r_vector_to_center, inverse_segment_magnitude); vert_location = vert_location_1; //if ((segp-Segments == 199) && (rsegp-Segments==199)) // Int3(); // Seg0 = segp-Segments; // Seg1 = rsegp-Segments; if (!quick_light) { int hash_value = Side_to_verts[sidenum][vertnum]; hash_info *hashp = &fvi_cache[hash_value]; while (1) { if (hashp->flag) { if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) { hit_type = hashp->hit_type; Hash_hits++; break; } else { Int3(); // How is this possible? Should be no hits! Hash_retries++; hash_value = (hash_value+1) & FVI_HASH_AND_MASK; hashp = &fvi_cache[hash_value]; } } else { fvi_query fq; Hash_calcs++; hashp->vector = vector_to_light; hashp->flag = 1; fq.p0 = &light_location; fq.startseg = segp-Segments; fq.p1 = &vert_location; fq.rad = 0; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; hit_type = find_vector_intersection(&fq,&hit_data); hashp->hit_type = hit_type; break; } } } else hit_type = HIT_NONE; switch (hit_type) { case HIT_NONE: light_at_point = fixmul(light_at_point, light_intensity); rsidep->uvls[vertnum].l += light_at_point; if (rsidep->uvls[vertnum].l > F1_0) rsidep->uvls[vertnum].l = F1_0; break; case HIT_WALL: break; case HIT_OBJECT: Int3(); // Hit object, should be ignoring objects! break; case HIT_BAD_P0: Int3(); // Ugh, this thing again, what happened, what does it mean? break; } } // end if (light_at_point... } // end if (light_dot >... } // end for (vertnum=0... } // end if (rsegp... } // end for (sidenum=0... } // end if (dist_to_rseg... } // end for (segnum=0... } // end for (lightnum=0... } // ------------------------------------------------------------------------------------------ // Zero all lighting values. void calim_zero_light_values(void) { int segnum, sidenum, vertnum; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; for (sidenum=0; sidenumsides[sidenum]; for (vertnum=0; vertnum<4; vertnum++) sidep->uvls[vertnum].l = F1_0/64; // Put a tiny bit of light here. } Segments[segnum].static_light = F1_0 / 64; } } // ------------------------------------------------------------------------------------------ // Used in setting average light value in a segment, cast light from a side to the center // of all segments. void cast_light_from_side_to_center(segment *segp, int light_side, fix light_intensity, int quick_light) { vms_vector segment_center; int segnum, lightnum; compute_segment_center(&segment_center, segp); // Do for four lights, one just inside each corner of side containing light. for (lightnum=0; lightnum<4; lightnum++) { int light_vertex_num; vms_vector vector_to_center; vms_vector light_location; light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]]; light_location = Vertices[light_vertex_num]; vm_vec_sub(&vector_to_center, &segment_center, &light_location); vm_vec_scale_add(&light_location, &light_location, &vector_to_center, F1_0/64); for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *rsegp = &Segments[segnum]; vms_vector r_segment_center; fix dist_to_rseg; //if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg])) // Int3(); compute_segment_center(&r_segment_center, rsegp); dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center); if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) { fix light_at_point; if (dist_to_rseg > F1_0) light_at_point = fixdiv(Magical_light_constant, dist_to_rseg); else light_at_point = Magical_light_constant; if (light_at_point >= 0) { int hit_type; if (!quick_light) { fvi_query fq; fvi_info hit_data; fq.p0 = &light_location; fq.startseg = segp-Segments; fq.p1 = &r_segment_center; fq.rad = 0; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; hit_type = find_vector_intersection(&fq,&hit_data); } else hit_type = HIT_NONE; switch (hit_type) { case HIT_NONE: light_at_point = fixmul(light_at_point, light_intensity); if (light_at_point >= F1_0) light_at_point = F1_0-1; rsegp->static_light += light_at_point; if (segp->static_light < 0) // if it went negative, saturate segp->static_light = 0; break; case HIT_WALL: break; case HIT_OBJECT: Int3(); // Hit object, should be ignoring objects! break; case HIT_BAD_P0: Int3(); // Ugh, this thing again, what happened, what does it mean? break; } } // end if (light_at_point... } // end if (dist_to_rseg... } // end for (segnum=0... } // end for (lightnum=0... } // ------------------------------------------------------------------------------------------ // Process all lights. void calim_process_all_lights(int quick_light) { int segnum, sidenum; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; for (sidenum=0; sidenumchildren[sidenum])) { if (WALL_IS_DOORWAY(segp, sidenum) != WID_NO_WALL) { side *sidep = &segp->sides[sidenum]; fix light_intensity; light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting; // if (segp->sides[sidenum].wall_num != -1) { // int wall_num, bitmap_num, effect_num; // wall_num = segp->sides[sidenum].wall_num; // effect_num = Walls[wall_num].type; // bitmap_num = effects_bm_num[effect_num]; // // light_intensity += TmapInfo[bitmap_num].lighting; // } if (light_intensity) { light_intensity /= 4; // casting light from four spots, so divide by 4. cast_light_from_side(segp, sidenum, light_intensity, quick_light); cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light); } } } } } // ------------------------------------------------------------------------------------------ // Apply static light in mine. // First, zero all light values. // Then, for all light sources, cast their light. void cast_all_light_in_mine(int quick_flag) { validate_segment_all(); calim_zero_light_values(); calim_process_all_lights(quick_flag); } // int Fvit_num = 1000; // // fix find_vector_intersection_test(void) // { // int i; // fvi_info hit_data; // int p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag; // fix rad; // int start_time = timer_get_milliseconds();; // vms_vector p0,p1; // // ignore_obj = 1; // check_obj_flag = 0; // this_objnum = -1; // rad = F1_0/4; // // for (i=0; ix - v2->x) < Normal_nearness) if (abs(v1->y - v2->y) < Normal_nearness) if (abs(v1->z - v2->z) < Normal_nearness) return 1; return 0; } int Total_normals=0; int Diff_normals=0; void print_normals(void) { int i,j,s,n,nn; // vms_vector *normal; int num_normals=0; Total_normals = 0; Diff_normals = 0; for (i=0; i<=Highest_segment_index; i++) for (s=0; s<6; s++) { if (Segments[i].sides[s].type == SIDE_IS_QUAD) nn=1; else nn=2; for (n=0; n #include #include #include #include "inferno.h" #include "gameseg.h" #include "screens.h" // For GAME_SCREEN????? #include "editor.h" // For TMAP_CURBOX?????? #include "gr.h" // For canves, font stuff #include "ui.h" // For UI_GADGET stuff #include "textures.h" // For NumTextures #include "dxxerror.h" #include "key.h" #include "gamesave.h" #include "mission.h" #include "texpage.h" #include "piggy.h" #define TMAPS_PER_PAGE 12 static UI_GADGET_USERBOX * TmapBox[TMAPS_PER_PAGE]; static UI_GADGET_USERBOX * TmapCurrent; int CurrentTexture = 0; // Used globally int TextureLights; int TextureEffects; int TextureMetals; static int TexturePage = 0; static grs_canvas * TmapnameCanvas; static char tmap_filename[13]; static void texpage_print_name( char name[13] ) { int w,h,aw; int i; for (i=strlen(name);i<12;i++) name[i]=' '; name[i]=0; gr_set_current_canvas( TmapnameCanvas ); gr_get_string_size( name, &w, &h, &aw ); gr_string( 0, 0, name ); } static void texpage_display_name( char *format, ... ) { va_list ap; va_start(ap, format); vsprintf(tmap_filename, format, ap); va_end(ap); texpage_print_name(tmap_filename); } //Redraw the list of textures, based on TexturePage void texpage_redraw() { int i; for (i = 0; i < TMAPS_PER_PAGE; i++) { gr_set_current_canvas(TmapBox[i]->canvas); if (i + TexturePage*TMAPS_PER_PAGE < NumTextures) { PIGGY_PAGE_IN(Textures[i + TexturePage*TMAPS_PER_PAGE]); gr_ubitmap(0, 0, &GameBitmaps[Textures[i + TexturePage*TMAPS_PER_PAGE].index]); } else gr_clear_canvas( CGREY ); } } //shows the current texture, updating the window and printing the name, base //on CurrentTexture void texpage_show_current() { gr_set_current_canvas(TmapCurrent->canvas); PIGGY_PAGE_IN(Textures[CurrentTexture]); gr_ubitmap(0,0, &GameBitmaps[Textures[CurrentTexture].index]); texpage_display_name( TmapInfo[CurrentTexture].filename ); } int texpage_goto_first() { TexturePage=0; texpage_redraw(); return 1; } int texpage_goto_metals() { TexturePage=TextureMetals/TMAPS_PER_PAGE; texpage_redraw(); return 1; } // Goto lights (paste ons) int texpage_goto_lights() { TexturePage=TextureLights/TMAPS_PER_PAGE; texpage_redraw(); return 1; } int texpage_goto_effects() { TexturePage=TextureEffects/TMAPS_PER_PAGE; texpage_redraw(); return 1; } static int texpage_goto_prev() { if (TexturePage > 0) { TexturePage--; texpage_redraw(); } return 1; } static int texpage_goto_next() { if ((TexturePage + 1)*TMAPS_PER_PAGE < NumTextures) { TexturePage++; texpage_redraw(); } return 1; } //NOTE: this code takes the texture map number, not this index in the //list of available textures. There are different if there are holes in //the list int texpage_grab_current(int n) { if ((n < 0) || (n >= NumTextures)) return 0; CurrentTexture = n; TexturePage = CurrentTexture / TMAPS_PER_PAGE; if (TexturePage*TMAPS_PER_PAGE < NumTextures) texpage_redraw(); texpage_show_current(); return 1; } // INIT TEXTURE STUFF void texpage_init( UI_DIALOG * dlg ) { int i; ui_add_gadget_button( dlg, TMAPCURBOX_X + 00, TMAPCURBOX_Y - 24, 30, 20, "<<", texpage_goto_prev ); ui_add_gadget_button( dlg, TMAPCURBOX_X + 32, TMAPCURBOX_Y - 24, 30, 20, ">>", texpage_goto_next ); ui_add_gadget_button( dlg, TMAPCURBOX_X + 00, TMAPCURBOX_Y - 48, 15, 20, "T", texpage_goto_first ); ui_add_gadget_button( dlg, TMAPCURBOX_X + 17, TMAPCURBOX_Y - 48, 15, 20, "M", texpage_goto_metals ); ui_add_gadget_button( dlg, TMAPCURBOX_X + 34, TMAPCURBOX_Y - 48, 15, 20, "L", texpage_goto_lights ); ui_add_gadget_button( dlg, TMAPCURBOX_X + 51, TMAPCURBOX_Y - 48, 15, 20, "E", texpage_goto_effects ); for (i=0;isc_canvas, TMAPCURBOX_X , TMAPCURBOX_Y + TMAPBOX_H + 10, 100, 20); } void texpage_close() { gr_free_sub_canvas(TmapnameCanvas); } // DO TEXTURE STUFF #define MAX_REPLACEMENTS 32 typedef struct replacement { int new, old; } replacement; replacement Replacement_list[MAX_REPLACEMENTS]; int Num_replacements=0; int texpage_do(d_event *event) { int i; if (event->type == EVENT_UI_DIALOG_DRAW) { gr_set_current_canvas( TmapnameCanvas ); gr_set_curfont( ui_small_font ); gr_set_fontcolor( CBLACK, CWHITE ); texpage_redraw(); gr_set_curfont(editor_font); // Don't reset the current tmap every time we go back to the editor. // CurrentTexture = TexturePage*TMAPS_PER_PAGE; texpage_show_current(); return 1; } for (i=0; i= 0); Assert(new_tmap_num >= 0); for (segnum=0; segnum <= Highest_segment_index; segnum++) { segment *segp=&Segments[segnum]; for (sidenum=0; sidenumsides[sidenum]; if (sidep->tmap_num == old_tmap_num) { sidep->tmap_num = new_tmap_num; } if ((sidep->tmap_num2 != 0) && ((sidep->tmap_num2 & 0x3fff) == old_tmap_num)) { if (new_tmap_num == 0) { Int3(); // Error. You have tried to replace a tmap_num2 with // the 0th tmap_num2 which is ILLEGAL! } else { sidep->tmap_num2 = new_tmap_num | (sidep->tmap_num2 & 0xc000); } } } } } } void do_replacements_all(void) { int i; for (i = 0; i < Last_level; i++) { load_level(Level_names[i]); do_replacements(); save_level(Level_names[i]); } for (i = 0; i < -Last_secret_level; i++) { load_level(Secret_level_names[i]); do_replacements(); save_level(Secret_level_names[i]); } } dxx-rebirth-0.58.1-d1x/editor/texture.c000066400000000000000000000221141217717257200177040ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Texture map assignment. * */ #include #include #include #include #include #include "inferno.h" #include "segment.h" #include "seguvs.h" #include "editor.h" #include "editor/esegment.h" #include "fix.h" #include "dxxerror.h" #include "kdefs.h" void compute_uv_side_center(uvl *uvcenter, segment *segp, int sidenum); void rotate_uv_points_on_side(segment *segp, int sidenum, fix *rotmat, uvl *uvcenter); // ----------------------------------------------------------- int TexFlipX() { uvl uvcenter; fix rotmat[4]; compute_uv_side_center(&uvcenter, Cursegp, Curside); // Create a rotation matrix rotmat[0] = -0xffff; rotmat[1] = 0; rotmat[2] = 0; rotmat[3] = 0xffff; rotate_uv_points_on_side(Cursegp, Curside, rotmat, &uvcenter); Update_flags |= UF_WORLD_CHANGED; return 1; } // ----------------------------------------------------------- int TexFlipY() { uvl uvcenter; fix rotmat[4]; compute_uv_side_center(&uvcenter, Cursegp, Curside); // Create a rotation matrix rotmat[0] = 0xffff; rotmat[1] = 0; rotmat[2] = 0; rotmat[3] = -0xffff; rotate_uv_points_on_side(Cursegp, Curside, rotmat, &uvcenter); Update_flags |= UF_WORLD_CHANGED; return 1; } // ----------------------------------------------------------- int DoTexSlideLeft(int value) { side *sidep; uvl duvl03; fix dist; sbyte *vp; int v; vp = Side_to_verts[Curside]; sidep = &Cursegp->sides[Curside]; dist = vm_vec_dist(&Vertices[Cursegp->verts[vp[3]]], &Vertices[Cursegp->verts[vp[0]]]); dist *= value; if (dist < F1_0/(64*value)) dist = F1_0/(64*value); duvl03.u = fixdiv(sidep->uvls[3].u - sidep->uvls[0].u,dist); duvl03.v = fixdiv(sidep->uvls[3].v - sidep->uvls[0].v,dist); for (v=0; v<4; v++) { sidep->uvls[v].u -= duvl03.u; sidep->uvls[v].v -= duvl03.v; } Update_flags |= UF_WORLD_CHANGED; return 1; } int TexSlideLeft() { return DoTexSlideLeft(3); } int TexSlideLeftBig() { return DoTexSlideLeft(1); } // ----------------------------------------------------------- int DoTexSlideUp(int value) { side *sidep; uvl duvl03; fix dist; sbyte *vp; int v; vp = Side_to_verts[Curside]; sidep = &Cursegp->sides[Curside]; dist = vm_vec_dist(&Vertices[Cursegp->verts[vp[1]]], &Vertices[Cursegp->verts[vp[0]]]); dist *= value; if (dist < F1_0/(64*value)) dist = F1_0/(64*value); duvl03.u = fixdiv(sidep->uvls[1].u - sidep->uvls[0].u,dist); duvl03.v = fixdiv(sidep->uvls[1].v - sidep->uvls[0].v,dist); for (v=0; v<4; v++) { sidep->uvls[v].u -= duvl03.u; sidep->uvls[v].v -= duvl03.v; } Update_flags |= UF_WORLD_CHANGED; return 1; } int TexSlideUp() { return DoTexSlideUp(3); } int TexSlideUpBig() { return DoTexSlideUp(1); } // ----------------------------------------------------------- int DoTexSlideDown(int value) { side *sidep; uvl duvl03; fix dist; sbyte *vp; int v; vp = Side_to_verts[Curside]; sidep = &Cursegp->sides[Curside]; dist = vm_vec_dist(&Vertices[Cursegp->verts[vp[1]]], &Vertices[Cursegp->verts[vp[0]]]); dist *= value; if (dist < F1_0/(64*value)) dist = F1_0/(64*value); duvl03.u = fixdiv(sidep->uvls[1].u - sidep->uvls[0].u,dist); duvl03.v = fixdiv(sidep->uvls[1].v - sidep->uvls[0].v,dist); for (v=0; v<4; v++) { sidep->uvls[v].u += duvl03.u; sidep->uvls[v].v += duvl03.v; } Update_flags |= UF_WORLD_CHANGED; return 1; } int TexSlideDown() { return DoTexSlideDown(3); } int TexSlideDownBig() { return DoTexSlideDown(1); } // ----------------------------------------------------------- // Compute the center of the side in u,v coordinates. void compute_uv_side_center(uvl *uvcenter, segment *segp, int sidenum) { int v; side *sidep = &segp->sides[sidenum]; uvcenter->u = 0; uvcenter->v = 0; for (v=0; v<4; v++) { uvcenter->u += sidep->uvls[v].u; uvcenter->v += sidep->uvls[v].v; } uvcenter->u /= 4; uvcenter->v /= 4; } // ----------------------------------------------------------- // rotate point *uv by matrix rotmat, return *uvrot void rotate_uv_point(uvl *uvrot, fix *rotmat, uvl *uv, uvl *uvcenter) { uvrot->u = fixmul(uv->u - uvcenter->u,rotmat[0]) + fixmul(uv->v - uvcenter->v,rotmat[1]) + uvcenter->u; uvrot->v = fixmul(uv->u - uvcenter->u,rotmat[2]) + fixmul(uv->v - uvcenter->v,rotmat[3]) + uvcenter->v; } // ----------------------------------------------------------- // Compute the center of the side in u,v coordinates. void rotate_uv_points_on_side(segment *segp, int sidenum, fix *rotmat, uvl *uvcenter) { int v; side *sidep = &segp->sides[sidenum]; uvl tuv; for (v=0; v<4; v++) { rotate_uv_point(&tuv, rotmat, &sidep->uvls[v], uvcenter); sidep->uvls[v] = tuv; } } // ----------------------------------------------------------- // ang is in 0..ffff = 0..359.999 degrees // rotmat is filled in with 4 fixes void create_2d_rotation_matrix(fix *rotmat, fix ang) { fix sinang, cosang; fix_sincos(ang, &sinang, &cosang); rotmat[0] = cosang; rotmat[1] = sinang; rotmat[2] = -sinang; rotmat[3] = cosang; } // ----------------------------------------------------------- int DoTexRotateLeft(int value) { uvl uvcenter; fix rotmat[4]; compute_uv_side_center(&uvcenter, Cursegp, Curside); // Create a rotation matrix create_2d_rotation_matrix(rotmat, -F1_0/value); rotate_uv_points_on_side(Cursegp, Curside, rotmat, &uvcenter); Update_flags |= UF_WORLD_CHANGED; return 1; } int TexRotateLeft() { return DoTexRotateLeft(192); } int TexRotateLeftBig() { return DoTexRotateLeft(64); } // ----------------------------------------------------------- int DoTexSlideRight(int value) { side *sidep; uvl duvl03; fix dist; sbyte *vp; int v; vp = Side_to_verts[Curside]; sidep = &Cursegp->sides[Curside]; dist = vm_vec_dist(&Vertices[Cursegp->verts[vp[3]]], &Vertices[Cursegp->verts[vp[0]]]); dist *= value; if (dist < F1_0/(64*value)) dist = F1_0/(64*value); duvl03.u = fixdiv(sidep->uvls[3].u - sidep->uvls[0].u,dist); duvl03.v = fixdiv(sidep->uvls[3].v - sidep->uvls[0].v,dist); for (v=0; v<4; v++) { sidep->uvls[v].u += duvl03.u; sidep->uvls[v].v += duvl03.v; } Update_flags |= UF_WORLD_CHANGED; return 1; } int TexSlideRight() { return DoTexSlideRight(3); } int TexSlideRightBig() { return DoTexSlideRight(1); } // ----------------------------------------------------------- int DoTexRotateRight(int value) { uvl uvcenter; fix rotmat[4]; compute_uv_side_center(&uvcenter, Cursegp, Curside); // Create a rotation matrix create_2d_rotation_matrix(rotmat, F1_0/value); rotate_uv_points_on_side(Cursegp, Curside, rotmat, &uvcenter); Update_flags |= UF_WORLD_CHANGED; return 1; } int TexRotateRight() { return DoTexRotateRight(192); } int TexRotateRightBig() { return DoTexRotateRight(64); } // ----------------------------------------------------------- int TexSelectActiveEdge() { return 1; } // ----------------------------------------------------------- int TexRotate90Degrees() { uvl uvcenter; fix rotmat[4]; compute_uv_side_center(&uvcenter, Cursegp, Curside); // Create a rotation matrix create_2d_rotation_matrix(rotmat, F1_0/4); rotate_uv_points_on_side(Cursegp, Curside, rotmat, &uvcenter); Update_flags |= UF_WORLD_CHANGED; return 1; } // ----------------------------------------------------------- int TexSetDefault() { Num_tilings = 1; Stretch_scale_x = F1_0; Stretch_scale_y = F1_0; assign_default_uvs_to_side(Cursegp,Curside); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } // ----------------------------------------------------------- int TexIncreaseTiling() { Num_tilings++; assign_default_uvs_to_side(Cursegp, Curside); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } // ----------------------------------------------------------- int TexDecreaseTiling() { if (--Num_tilings < 1) Num_tilings = 1; assign_default_uvs_to_side(Cursegp, Curside); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } // direction = -1 or 1 depending on direction int TexStretchCommon(int direction) { fix *sptr; if ((Curedge == 0) || (Curedge == 2)) sptr = &Stretch_scale_x; else sptr = &Stretch_scale_y; *sptr += direction*F1_0/64; if (*sptr < F1_0/16) *sptr = F1_0/16; if (*sptr > 2*F1_0) *sptr = 2*F1_0; stretch_uvs_from_curedge(Cursegp, Curside); editor_status_fmt("Stretch scale = %7.4f, use Set Default to return to 1.0", f2fl(*sptr)); Update_flags |= UF_GAME_VIEW_CHANGED; return 1; } int TexStretchDown(void) { return TexStretchCommon(-1); } int TexStretchUp(void) { return TexStretchCommon(1); } dxx-rebirth-0.58.1-d1x/iff/000077500000000000000000000000001217717257200153165ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/iff/iff.c000066400000000000000000000601651217717257200162360ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for reading and writing IFF files * */ #define COMPRESS 1 //do the RLE or not? (for debugging mostly) #define WRITE_TINY 0 //should we write a TINY chunk? #define MIN_COMPRESS_WIDTH 65 //don't compress if less than this wide #include #include #include #include "u_mem.h" #include "iff.h" #include "dxxerror.h" #include "physfsx.h" //Internal constants and structures for this library extern void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); //Type values for bitmaps #define TYPE_PBM 0 #define TYPE_ILBM 1 //Compression types #define cmpNone 0 #define cmpByteRun1 1 //Masking types #define mskNone 0 #define mskHasMask 1 #define mskHasTransparentColor 2 //Palette entry structure typedef struct pal_entry {sbyte r,g,b;} pal_entry; //structure of the header in the file typedef struct iff_bitmap_header { short w,h; //width and height of this bitmap short x,y; //generally unused short type; //see types above short transparentcolor; //which color is transparent (if any) short pagewidth,pageheight; //width & height of source screen sbyte nplanes; //number of planes (8 for 256 color image) sbyte masking,compression; //see constants above sbyte xaspect,yaspect; //aspect ratio (usually 5/6) pal_entry palette[256]; //the palette for this bitmap ubyte *raw_data; //ptr to array of data short row_size; //offset to next row } iff_bitmap_header; ubyte iff_transparent_color; ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid #define MAKE_SIG(a,b,c,d) (((int32_t)(a)<<24)+((int32_t)(b)<<16)+((c)<<8)+(d)) #define form_sig MAKE_SIG('F','O','R','M') #define ilbm_sig MAKE_SIG('I','L','B','M') #define body_sig MAKE_SIG('B','O','D','Y') #define pbm_sig MAKE_SIG('P','B','M',' ') #define bmhd_sig MAKE_SIG('B','M','H','D') #define anhd_sig MAKE_SIG('A','N','H','D') #define cmap_sig MAKE_SIG('C','M','A','P') #define tiny_sig MAKE_SIG('T','I','N','Y') #define anim_sig MAKE_SIG('A','N','I','M') #define dlta_sig MAKE_SIG('D','L','T','A') int32_t get_sig(PHYSFS_file *f) { int s; PHYSFS_readSBE32(f, &s); return s; } #define put_sig(sig, f) PHYSFS_writeSBE32(f, sig) int parse_bmhd(PHYSFS_file *ifile,long len,iff_bitmap_header *bmheader) { len++; /* so no "parm not used" warning */ // debug("parsing bmhd len=%ld\n",len); PHYSFS_readSBE16(ifile, &bmheader->w); PHYSFS_readSBE16(ifile, &bmheader->h); PHYSFS_readSBE16(ifile, &bmheader->x); PHYSFS_readSBE16(ifile, &bmheader->y); bmheader->nplanes = PHYSFSX_readByte(ifile); bmheader->masking = PHYSFSX_readByte(ifile); bmheader->compression = PHYSFSX_readByte(ifile); PHYSFSX_readByte(ifile); /* skip pad */ PHYSFS_readSBE16(ifile, &bmheader->transparentcolor); bmheader->xaspect = PHYSFSX_readByte(ifile); bmheader->yaspect = PHYSFSX_readByte(ifile); PHYSFS_readSBE16(ifile, &bmheader->pagewidth); PHYSFS_readSBE16(ifile, &bmheader->pageheight); iff_transparent_color = (unsigned char)bmheader->transparentcolor; iff_has_transparency = 0; if (bmheader->masking == mskHasTransparentColor) iff_has_transparency = 1; else if (bmheader->masking != mskNone && bmheader->masking != mskHasMask) return IFF_UNKNOWN_MASK; // debug("w,h=%d,%d x,y=%d,%d\n",w,h,x,y); // debug("nplanes=%d, masking=%d ,compression=%d, transcolor=%d\n",nplanes,masking,compression,transparentcolor); return IFF_NO_ERROR; } // the buffer pointed to by raw_data is stuffed with a pointer to decompressed pixel data int parse_body(PHYSFS_file *ifile,long len,iff_bitmap_header *bmheader) { unsigned char *p=bmheader->raw_data; int width,depth; signed char n; int nn,wid_cnt,end_cnt,plane; unsigned char *data_end; int end_pos; #ifndef NDEBUG int row_count=0; #endif width=0; depth=0; end_pos = PHYSFS_tell(ifile) + len; if (len&1) end_pos++; if (bmheader->type == TYPE_PBM) { width=bmheader->w; depth=1; } else if (bmheader->type == TYPE_ILBM) { width = (bmheader->w+7)/8; depth=bmheader->nplanes; } end_cnt = (width&1)?-1:0; data_end = p + width*bmheader->h*depth; if (bmheader->compression == cmpNone) { /* no compression */ int y; for (y=bmheader->h;y;y--) { PHYSFS_read(ifile, p, width, depth); p += bmheader->w; if (bmheader->masking == mskHasMask) PHYSFSX_fseek(ifile, width, SEEK_CUR); //skip mask! if (bmheader->w & 1) PHYSFSX_fgetc(ifile); } //cnt = len - bmheader->h * ((bmheader->w+1)&~1); } else if (bmheader->compression == cmpByteRun1) for (wid_cnt=width,plane=0; PHYSFS_tell(ifile) < end_pos && pmasking == mskHasMask && plane==depth+1) || (bmheader->masking != mskHasMask && plane==depth)) plane=0; } Assert(wid_cnt > end_cnt); n=PHYSFSX_fgetc(ifile); if (n >= 0) { // copy next n+1 bytes from source, they are not compressed nn = (int) n+1; wid_cnt -= nn; if (wid_cnt==-1) {--nn; Assert(width&1);} if (plane==depth) //masking row PHYSFSX_fseek(ifile, nn, SEEK_CUR); else { PHYSFS_read(ifile, p, nn, 1); p += nn; } if (wid_cnt==-1) PHYSFSX_fseek(ifile, 1, SEEK_CUR); } else if (n>=-127) { // next -n + 1 bytes are following byte c=PHYSFSX_fgetc(ifile); nn = (int) -n+1; wid_cnt -= nn; if (wid_cnt==-1) {--nn; Assert(width&1);} if (plane!=depth) //not masking row {memset(p,c,nn); p+=nn;} } #ifndef NDEBUG if ((p-bmheader->raw_data) % width == 0) row_count++; Assert((p-bmheader->raw_data) - (width*row_count) < width); #endif } if (bmheader->masking==mskHasMask && p==data_end && PHYSFS_tell(ifile)==end_pos-2) //I don't know why... PHYSFSX_fseek(ifile, 1, SEEK_CUR); //...but if I do this it works if (p==data_end && PHYSFS_tell(ifile)==end_pos-1) //must be a pad byte //ignore = PHYSFSX_fgetc(ifile); //get pad byte PHYSFSX_fseek(ifile, 1, SEEK_CUR); else if (PHYSFS_tell(ifile)!=end_pos || p!=data_end) { // debug("IFF Error: p=%x, data_end=%x, cnt=%d\n",p,data_end,cnt); return IFF_CORRUPT; } return IFF_NO_ERROR; } //modify passed bitmap int parse_delta(PHYSFS_file *ifile,long len,iff_bitmap_header *bmheader) { unsigned char *p=bmheader->raw_data; int y; long chunk_end = PHYSFS_tell(ifile) + len; PHYSFSX_fseek(ifile, 4, SEEK_CUR); //longword, seems to be equal to 4. Don't know what it is for (y=0;yh;y++) { ubyte n_items; int cnt = bmheader->w; ubyte code; n_items = PHYSFSX_readByte(ifile); while (n_items--) { code = PHYSFSX_readByte(ifile); if (code==0) { //repeat ubyte rep,val; rep = PHYSFSX_readByte(ifile); val = PHYSFSX_readByte(ifile); cnt -= rep; if (cnt==-1) rep--; while (rep--) *p++ = val; } else if (code > 0x80) { //skip cnt -= (code-0x80); p += (code-0x80); if (cnt==-1) p--; } else { //literal cnt -= code; if (cnt==-1) code--; while (code--) *p++ = PHYSFSX_readByte(ifile); if (cnt==-1) PHYSFSX_readByte(ifile); } } if (cnt == -1) { if (!bmheader->w&1) return IFF_CORRUPT; } else if (cnt) return IFF_CORRUPT; } if (PHYSFS_tell(ifile) == chunk_end-1) //pad PHYSFSX_fseek(ifile, 1, SEEK_CUR); if (PHYSFS_tell(ifile) != chunk_end) return IFF_CORRUPT; else return IFF_NO_ERROR; } // the buffer pointed to by raw_data is stuffed with a pointer to bitplane pixel data void skip_chunk(PHYSFS_file *ifile,long len) { int ilen; ilen = (len+1) & ~1; PHYSFSX_fseek(ifile,ilen,SEEK_CUR); } //read an ILBM or PBM file // Pass pointer to opened file, and to empty bitmap_header structure, and form length int iff_parse_ilbm_pbm(PHYSFS_file *ifile,long form_type,iff_bitmap_header *bmheader,int form_len,grs_bitmap *prev_bm) { int sig,len; long start_pos,end_pos; start_pos = PHYSFS_tell(ifile); end_pos = start_pos-4+form_len; if (form_type == pbm_sig) bmheader->type = TYPE_PBM; else bmheader->type = TYPE_ILBM; while ((PHYSFS_tell(ifile) < end_pos) && (sig=get_sig(ifile)) != EOF) { if (PHYSFS_readSBE32(ifile, &len)==EOF) break; switch (sig) { case bmhd_sig: { int ret; int save_w=bmheader->w,save_h=bmheader->h; ret = parse_bmhd(ifile,len,bmheader); if (ret != IFF_NO_ERROR) return ret; if (bmheader->raw_data) { if (save_w != bmheader->w || save_h != bmheader->h) return IFF_BM_MISMATCH; } else { MALLOC( bmheader->raw_data, ubyte, bmheader->w * bmheader->h ); if (!bmheader->raw_data) return IFF_NO_MEM; } break; } case anhd_sig: if (!prev_bm) return IFF_CORRUPT; // initialized the new bitmap gr_init_bitmap ( (grs_bitmap*) bmheader, prev_bm->bm_type, 0, 0, prev_bm->bm_w, prev_bm->bm_h, prev_bm->bm_rowsize, 0); // and copy gr_bm_bitblt(prev_bm->bm_w, prev_bm->bm_h, 0, 0, 0, 0, prev_bm, (grs_bitmap*) bmheader); skip_chunk(ifile,len); break; case cmap_sig: { int ncolors=(int) (len/3),cnum; unsigned char r,g,b; for (cnum=0;cnum>= 2; bmheader->palette[cnum].r = r; g >>= 2; bmheader->palette[cnum].g = g; b >>= 2; bmheader->palette[cnum].b = b; } if (len & 1) PHYSFSX_fgetc(ifile); break; } case body_sig: { int r; if ((r=parse_body(ifile,len,bmheader))!=IFF_NO_ERROR) return r; break; } case dlta_sig: { int r; if ((r=parse_delta(ifile,len,bmheader))!=IFF_NO_ERROR) return r; break; } default: skip_chunk(ifile,len); break; } } if (PHYSFS_tell(ifile) != start_pos-4+form_len) return IFF_CORRUPT; return IFF_NO_ERROR; /* ok! */ } //convert an ILBM file to a PBM file int convert_ilbm_to_pbm(iff_bitmap_header *bmheader) { int x,y,p; sbyte *new_data, *destptr, *rowptr; int bytes_per_row,byteofs; ubyte checkmask,newbyte,setbit; MALLOC(new_data, sbyte, bmheader->w * bmheader->h); if (new_data == NULL) return IFF_NO_MEM; destptr = new_data; bytes_per_row = 2*((bmheader->w+15)/16); for (y=0;yh;y++) { rowptr = (signed char *) &bmheader->raw_data[y * bytes_per_row * bmheader->nplanes]; for (x=0,checkmask=0x80;xw;x++) { byteofs = x >> 3; for (p=newbyte=0,setbit=1;pnplanes;p++) { if (rowptr[bytes_per_row * p + byteofs] & checkmask) newbyte |= setbit; setbit <<= 1; } *destptr++ = newbyte; if ((checkmask >>= 1) == 0) checkmask=0x80; } } d_free(bmheader->raw_data); bmheader->raw_data = (unsigned char *) new_data; bmheader->type = TYPE_PBM; return IFF_NO_ERROR; } #define INDEX_TO_15BPP(i) ((short)((((palptr[(i)].r/2)&31)<<10)+(((palptr[(i)].g/2)&31)<<5)+((palptr[(i)].b/2 )&31))) int convert_rgb15(grs_bitmap *bm,iff_bitmap_header *bmheader) { int x,y; // int newptr = 0; pal_entry *palptr; palptr = bmheader->palette; gr_init_bitmap (bm, bm->bm_type, 0, 0, bm->bm_w, bm->bm_h, bm->bm_rowsize, 0); for (y=0; ybm_h; y++) { for (x=0; xw; x++) gr_bm_pixel (bm, x, y, INDEX_TO_15BPP(bmheader->raw_data[y*bmheader->w+x])); } return IFF_NO_ERROR; } //copy an iff header structure to a grs_bitmap structure void copy_iff_to_grs(grs_bitmap *bm,iff_bitmap_header *bmheader) { gr_init_bitmap (bm, bmheader->type, 0, 0, bmheader->w, bmheader->h, bmheader->w, bmheader->raw_data); } //if bm->bm_data is set, use it (making sure w & h are correct), else //allocate the memory int iff_parse_bitmap(PHYSFS_file *ifile, grs_bitmap *bm, int bitmap_type, sbyte *palette, grs_bitmap *prev_bm) { int ret; //return code iff_bitmap_header bmheader; int sig,form_len; long form_type; bmheader.raw_data = bm->bm_data; if (bmheader.raw_data) { bmheader.w = bm->bm_w; bmheader.h = bm->bm_h; }//added 05/17/99 Matt Mueller - don't just leave them unitialized else{ bmheader.w=bmheader.h=0; } //end addition -MM sig=get_sig(ifile); if (sig != form_sig) { ret = IFF_NOT_IFF; goto done; } PHYSFS_readSBE32(ifile, &form_len); form_type = get_sig(ifile); if (form_type == anim_sig) ret = IFF_FORM_ANIM; else if ((form_type == pbm_sig) || (form_type == ilbm_sig)) ret = iff_parse_ilbm_pbm(ifile,form_type,&bmheader,form_len,prev_bm); else ret = IFF_UNKNOWN_FORM; if (ret != IFF_NO_ERROR) { //got an error parsing if (bmheader.raw_data) d_free(bmheader.raw_data); goto done; } //If IFF file is ILBM, convert to PPB if (bmheader.type == TYPE_ILBM) { ret = convert_ilbm_to_pbm(&bmheader); if (ret != IFF_NO_ERROR) goto done; } //Copy data from iff_bitmap_header structure into grs_bitmap structure copy_iff_to_grs(bm,&bmheader); if (palette) memcpy(palette,&bmheader.palette,sizeof(bmheader.palette)); //Now do post-process if required if (bitmap_type == BM_RGB15) { ret = convert_rgb15(bm,&bmheader); if (ret != IFF_NO_ERROR) goto done; } done: return ret; } //returns error codes - see IFF.H. see GR.H for bitmap_type int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette) { int ret; //return code PHYSFS_file *ifile; ifile = PHYSFSX_openReadBuffered(ifilename); if (ifile == NULL) return IFF_NO_FILE; bm->bm_data = NULL; ret = iff_parse_bitmap(ifile,bm,bitmap_type,(signed char *) palette,NULL); PHYSFS_close(ifile); return ret; } //like iff_read_bitmap(), but reads into a bitmap that already exists, //without allocating memory for the bitmap. int iff_read_into_bitmap(char *ifilename, grs_bitmap *bm, sbyte *palette) { int ret; //return code PHYSFS_file *ifile; ifile = PHYSFSX_openReadBuffered(ifilename); if (ifile == NULL) return IFF_NO_FILE; ret = iff_parse_bitmap(ifile,bm,bm->bm_type,palette,NULL); PHYSFS_close(ifile); return ret; } #define BMHD_SIZE 20 int write_bmhd(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header) { put_sig(bmhd_sig,ofile); PHYSFS_writeSBE32(ofile, BMHD_SIZE); PHYSFS_writeSBE16(ofile, bitmap_header->w); PHYSFS_writeSBE16(ofile, bitmap_header->h); PHYSFS_writeSBE16(ofile, bitmap_header->x); PHYSFS_writeSBE16(ofile, bitmap_header->y); PHYSFSX_writeU8(ofile, bitmap_header->nplanes); PHYSFSX_writeU8(ofile, bitmap_header->masking); PHYSFSX_writeU8(ofile, bitmap_header->compression); PHYSFSX_writeU8(ofile, 0); /* pad */ PHYSFS_writeSBE16(ofile, bitmap_header->transparentcolor); PHYSFSX_writeU8(ofile, bitmap_header->xaspect); PHYSFSX_writeU8(ofile, bitmap_header->yaspect); PHYSFS_writeSBE16(ofile, bitmap_header->pagewidth); PHYSFS_writeSBE16(ofile, bitmap_header->pageheight); return IFF_NO_ERROR; } int write_pal(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header) { int i; int n_colors = 1<nplanes; put_sig(cmap_sig,ofile); // PHYSFS_writeSBE32(sizeof(pal_entry) * n_colors,ofile); PHYSFS_writeSBE32(ofile, 3 * n_colors); for (i=0; i<256; i++) { unsigned char r,g,b; r = bitmap_header->palette[i].r * 4 + (bitmap_header->palette[i].r?3:0); g = bitmap_header->palette[i].g * 4 + (bitmap_header->palette[i].g?3:0); b = bitmap_header->palette[i].b * 4 + (bitmap_header->palette[i].b?3:0); PHYSFSX_writeU8(ofile, r); PHYSFSX_writeU8(ofile, g); PHYSFSX_writeU8(ofile, b); } return IFF_NO_ERROR; } int rle_span(ubyte *dest,ubyte *src,int len) { int n,lit_cnt,rep_cnt; ubyte last,*cnt_ptr,*dptr; cnt_ptr=0; dptr = dest; last=src[0]; lit_cnt=1; for (n=1;n 2 || lit_cnt < 2) { if (lit_cnt > 1) {*cnt_ptr = lit_cnt-2; --dptr;} //save old lit count *dptr++ = -(rep_cnt-1); *dptr++ = last; last = src[n]; lit_cnt = (n 1) *cnt_ptr = lit_cnt-1; return dptr-dest; } #define EVEN(a) ((a+1)&0xfffffffel) //returns length of chunk int write_body(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on) { int w=bitmap_header->w,h=bitmap_header->h; int y,odd=w&1; long len = EVEN(w) * h,newlen,total_len=0; ubyte *p=bitmap_header->raw_data,*new_span; long save_pos; put_sig(body_sig,ofile); save_pos = PHYSFS_tell(ofile); PHYSFS_writeSBE32(ofile, len); //if (! (new_span = malloc(bitmap_header->w+(bitmap_header->w/128+2)*2))) return IFF_NO_MEM; MALLOC( new_span, ubyte, bitmap_header->w + (bitmap_header->w/128+2));//adb: removed *2 if (new_span == NULL) return IFF_NO_MEM; for (y=bitmap_header->h;y--;) { if (compression_on) { total_len += newlen = rle_span(new_span,p,bitmap_header->w+odd); PHYSFS_write(ofile,new_span,newlen,1); } else PHYSFS_write(ofile,p,bitmap_header->w+odd,1); p+=bitmap_header->row_size; //bitmap_header->w; } if (compression_on) { //write actual data length Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); (void)save_pos; PHYSFS_writeSBE32(ofile, total_len); Assert(PHYSFSX_fseek(ofile,total_len,SEEK_CUR)==0); if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even } d_free(new_span); return ((compression_on) ? (EVEN(total_len)+8) : (len+8)); } #if WRITE_TINY //write a small representation of a bitmap. returns size int write_tiny(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on) { int skip; int new_w,new_h; int len,total_len=0,newlen; int x,y,xofs,odd; ubyte *p = bitmap_header->raw_data; ubyte tspan[80],new_span[80*2]; long save_pos; skip = max((bitmap_header->w+79)/80,(bitmap_header->h+63)/64); new_w = bitmap_header->w / skip; new_h = bitmap_header->h / skip; odd = new_w & 1; len = new_w * new_h + 4; put_sig(tiny_sig,ofile); save_pos = PHYSFS_tell(ofile); PHYSFS_writeSBE32(ofile, EVEN(len)); PHYSFS_writeSBE16(ofile, new_w); PHYSFS_writeSBE16(ofile, new_h); for (y=0;yrow_size; //bitmap_header->w; } if (compression_on) { Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); (void)save_pos; PHYSFS_writeSBE32(ofile, 4+total_len); Assert(PHYSFSX_fseek(ofile,4+total_len,SEEK_CUR)==0); if (total_len&1) PHYSFSX_writeU8(ofile, 0); //pad to even } return ((compression_on) ? (EVEN(total_len)+8+4) : (len+8)); } #endif int write_pbm(PHYSFS_file *ofile,iff_bitmap_header *bitmap_header,int compression_on) /* writes a pbm iff file */ { int ret; long raw_size = EVEN(bitmap_header->w) * bitmap_header->h; long body_size,tiny_size,pbm_size = 4 + BMHD_SIZE + 8 + EVEN(raw_size) + sizeof(pal_entry)*(1<nplanes)+8; long save_pos; put_sig(form_sig,ofile); save_pos = PHYSFS_tell(ofile); PHYSFS_writeSBE32(ofile, pbm_size+8); put_sig(pbm_sig,ofile); ret = write_bmhd(ofile,bitmap_header); if (ret != IFF_NO_ERROR) return ret; ret = write_pal(ofile,bitmap_header); if (ret != IFF_NO_ERROR) return ret; #if WRITE_TINY tiny_size = write_tiny(ofile,bitmap_header,compression_on); #else tiny_size = 0; #endif body_size = write_body(ofile,bitmap_header,compression_on); pbm_size = 4 + BMHD_SIZE + body_size + tiny_size + sizeof(pal_entry)*(1<nplanes)+8; Assert(PHYSFSX_fseek(ofile,save_pos,SEEK_SET)==0); (void)save_pos; PHYSFS_writeSBE32(ofile, pbm_size+8); Assert(PHYSFSX_fseek(ofile,pbm_size+8,SEEK_CUR)==0); return ret; } //writes an IFF file from a grs_bitmap structure. writes palette if not null //returns error codes - see IFF.H. int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette) { PHYSFS_file *ofile; iff_bitmap_header bmheader; int ret; int compression_on; if (bm->bm_type == BM_RGB15) return IFF_BAD_BM_TYPE; #if COMPRESS compression_on = (bm->bm_w>=MIN_COMPRESS_WIDTH); #else compression_on = 0; #endif //fill in values in bmheader bmheader.x = bmheader.y = 0; bmheader.w = bm->bm_w; bmheader.h = bm->bm_h; bmheader.type = TYPE_PBM; bmheader.transparentcolor = iff_transparent_color; bmheader.pagewidth = bm->bm_w; //I don't think it matters what I write bmheader.pageheight = bm->bm_h; bmheader.nplanes = 8; bmheader.masking = mskNone; if (iff_has_transparency) { bmheader.masking |= mskHasTransparentColor; } bmheader.compression = (compression_on?cmpByteRun1:cmpNone); bmheader.xaspect = bmheader.yaspect = 1; //I don't think it matters what I write bmheader.raw_data = bm->bm_data; bmheader.row_size = bm->bm_rowsize; if (palette) memcpy(&bmheader.palette,palette,256*3); //open file and write if ((ofile = PHYSFS_openWrite(ofilename)) == NULL) return IFF_NO_FILE; ret = write_pbm(ofile,&bmheader,compression_on); PHYSFS_close(ofile); return ret; } //read in many brushes. fills in array of pointers, and n_bitmaps. //returns iff error codes int iff_read_animbrush(char *ifilename,grs_bitmap **bm_list,int max_bitmaps,int *n_bitmaps,ubyte *palette) { int ret = IFF_NO_ERROR; //return code PHYSFS_file *ifile; int sig,form_len; long form_type; *n_bitmaps=0; ifile = PHYSFSX_openReadBuffered(ifilename); if (ifile == NULL) return IFF_NO_FILE; sig=get_sig(ifile); PHYSFS_readSBE32(ifile, &form_len); if (sig != form_sig) { ret = IFF_NOT_IFF; goto done; } form_type = get_sig(ifile); if ((form_type == pbm_sig) || (form_type == ilbm_sig)) ret = IFF_FORM_BITMAP; else if (form_type == anim_sig) { int anim_end = PHYSFS_tell(ifile) + form_len - 4; while (PHYSFS_tell(ifile) < anim_end && *n_bitmaps < max_bitmaps) { grs_bitmap *prev_bm; prev_bm = *n_bitmaps>0?bm_list[*n_bitmaps-1]:NULL; MALLOC(bm_list[*n_bitmaps] , grs_bitmap, 1 ); bm_list[*n_bitmaps]=(grs_bitmap *)d_malloc(1*sizeof(grs_bitmap)); gr_init_bitmap_data ((grs_bitmap *) &bm_list[*n_bitmaps]); ret = iff_parse_bitmap(ifile,bm_list[*n_bitmaps],form_type,*n_bitmaps>0?NULL:(signed char *)palette,prev_bm); if (ret != IFF_NO_ERROR) goto done; (*n_bitmaps)++; } if (PHYSFS_tell(ifile) < anim_end) //ran out of room ret = IFF_TOO_MANY_BMS; } else ret = IFF_UNKNOWN_FORM; done: PHYSFS_close(ifile); return ret; } //text for error messges static const char error_messages[] = { "No error.\0" "Not enough mem for loading or processing bitmap.\0" "IFF file has unknown FORM type.\0" "Not an IFF file.\0" "Cannot open file.\0" "Tried to save invalid type, like BM_RGB15.\0" "Bad data in file.\0" "ANIM file cannot be loaded with normal bitmap loader.\0" "Normal bitmap file cannot be loaded with anim loader.\0" "Array not big enough on anim brush read.\0" "Unknown mask type in bitmap header.\0" "Error reading file.\0" }; //function to return pointer to error message const char *iff_errormsg(int error_number) { const char *p = error_messages; while (error_number--) { if (!p) return NULL; p += strlen(p)+1; } return p; } dxx-rebirth-0.58.1-d1x/include/000077500000000000000000000000001217717257200161755ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/include/3d.h000066400000000000000000000221261217717257200166570ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/3d.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:06 $ * * Header file for 3d library * * $Log: 3d.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:06 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:02:03 donut * Import of d1x 1.37 source. * * Revision 1.2 1995/09/14 14:08:58 allender * return value for g3_draw_sphere * * Revision 1.1 1995/05/05 08:48:41 allender * Initial revision * * * */ #ifndef _3D_H #define _3D_H #include "fix.h" #include "vecmat.h" //the vector/matrix library #include "gr.h" extern int g3d_interp_outline; //if on, polygon models outlined in white extern vms_vector Matrix_scale; //how the matrix is currently scaled extern short highest_texture_num; //Structure for storing u,v,light values. This structure doesn't have a //prefix because it was defined somewhere else before it was moved here typedef struct g3s_uvl { fix u,v,l; } g3s_uvl; //Structure for storing light color. Also uses l of g3s-uvl to add/compute mono (white) light typedef struct g3s_lrgb { fix r,g,b; } g3s_lrgb; //Stucture to store clipping codes in a word typedef struct g3s_codes { ubyte uor,uand; //or is low byte, and is high byte } g3s_codes; //flags for point structure #define PF_PROJECTED 1 //has been projected, so sx,sy valid #define PF_OVERFLOW 2 //can't project #define PF_TEMP_POINT 4 //created during clip #define PF_UVS 8 //has uv values set #define PF_LS 16 //has lighting values set //clipping codes flags #define CC_OFF_LEFT 1 #define CC_OFF_RIGHT 2 #define CC_OFF_BOT 4 #define CC_OFF_TOP 8 #define CC_BEHIND 0x80 //Used to store rotated points for mines. Has frame count to indictate //if rotated, and flag to indicate if projected. typedef struct g3s_point { vms_vector p3_vec; //reference as vector... fix p3_u,p3_v,p3_l; fix p3_sx,p3_sy; //screen x&y ubyte p3_codes; //clipping codes ubyte p3_flags; //projected? short p3_pad; //keep structure longwork aligned } g3s_point; //macros to reference x,y,z elements of a 3d point #define p3_x p3_vec.x #define p3_y p3_vec.y #define p3_z p3_vec.z //An object, such as a robot typedef struct g3s_object { vms_vector o3_pos; //location of this object vms_angvec o3_orient; //orientation of this object int o3_nverts; //number of points in the object int o3_nfaces; //number of faces in the object //this will be filled in later } g3s_object; //Functions in library //3d system startup and shutdown: //Frame setup functions: //start the frame void g3_start_frame(void); //set view from x,y,z & p,b,h, zoom. Must call one of g3_set_view_*() void g3_set_view_angles(vms_vector *view_pos,vms_angvec *view_orient,fix zoom); //set view from x,y,z, viewer matrix, and zoom. Must call one of g3_set_view_*() void g3_set_view_matrix(vms_vector *view_pos,vms_matrix *view_matrix,fix zoom); //end the frame void g3_end_frame(void); //draw a horizon void g3_draw_horizon(int sky_color,int ground_color); //get vectors that are edge of horizon int g3_compute_sky_polygon(fix *points_2d,vms_vector *vecs); //Instancing //instance at specified point with specified orientation void g3_start_instance_matrix(vms_vector *pos,vms_matrix *orient); //instance at specified point with specified orientation void g3_start_instance_angles(vms_vector *pos,vms_angvec *angles); //pops the old context void g3_done_instance(); //Misc utility functions: //get current field of view. Fills in angle for x & y void g3_get_FOV(fixang *fov_x,fixang *fov_y); //get zoom. For a given window size, return the zoom which will achieve //the given FOV along the given axis. fix g3_get_zoom(char axis,fixang fov,short window_width,short window_height); //returns the normalized, unscaled view vectors void g3_get_view_vectors(vms_vector *forward,vms_vector *up,vms_vector *right); //returns true if a plane is facing the viewer. takes the unrotated surface //normal of the plane, and a point on it. The normal need not be normalized bool g3_check_normal_facing(vms_vector *v,vms_vector *norm); //Point definition and rotation functions: //specify the arrays refered to by the 'pointlist' parms in the following //functions. I'm not sure if we will keep this function, but I need //it now. //void g3_set_points(g3s_point *points,vms_vector *vecs); //returns codes_and & codes_or of a list of points numbers g3s_codes g3_check_codes(int nv,g3s_point **pointlist); //rotates a point. returns codes. does not check if already rotated ubyte g3_rotate_point(g3s_point *dest,const vms_vector *src); //projects a point void g3_project_point(g3s_point *point); //calculate the depth of a point - returns the z coord of the rotated point fix g3_calc_point_depth(vms_vector *pnt); //from a 2d point, compute the vector through that point void g3_point_2_vec(vms_vector *v,short sx,short sy); //code a point. fills in the p3_codes field of the point, and returns the codes ubyte g3_code_point(g3s_point *point); //delta rotation functions vms_vector *g3_rotate_delta_x(vms_vector *dest,fix dx); vms_vector *g3_rotate_delta_y(vms_vector *dest,fix dy); vms_vector *g3_rotate_delta_z(vms_vector *dest,fix dz); vms_vector *g3_rotate_delta_vec(vms_vector *dest,vms_vector *src); ubyte g3_add_delta_vec(g3s_point *dest,g3s_point *src,vms_vector *deltav); //Drawing functions: //draw a flat-shaded face. //returns 1 if off screen, 0 if drew bool g3_draw_poly(int nv,g3s_point **pointlist); //draw a texture-mapped face. //returns 1 if off screen, 0 if drew bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm); //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d //radius, but not to the distance from the eye int g3_draw_sphere(g3s_point *pnt,fix rad); //@@//return ligting value for a point //@@fix g3_compute_lighting_value(g3s_point *rotated_point,fix normval); //like g3_draw_poly(), but checks to see if facing. If surface normal is //NULL, this routine must compute it, which will be slow. It is better to //pre-compute the normal, and pass it to this function. When the normal //is passed, this function works like g3_check_normal_facing() plus //g3_draw_poly(). //returns -1 if not facing, 1 if off screen, 0 if drew bool g3_check_and_draw_poly(int nv,g3s_point **pointlist,vms_vector *norm,vms_vector *pnt); bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb, grs_bitmap *bm,vms_vector *norm,vms_vector *pnt); //draws a line. takes two points. bool g3_draw_line(g3s_point *p0,g3s_point *p1); //draw a polygon that is always facing you //returns 1 if off screen, 0 if drew bool g3_draw_rod_flat(g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width); //draw a bitmap object that is always facing you //returns 1 if off screen, 0 if drew bool g3_draw_rod_tmap(grs_bitmap *bitmap,g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width,g3s_lrgb light); //draws a bitmap with the specified 3d width & height //returns 1 if off screen, 0 if drew bool g3_draw_bitmap(vms_vector *pos,fix width,fix height,grs_bitmap *bm); //specifies 2d drawing routines to use instead of defaults. Passing //NULL for either or both restores defaults typedef void (*tmap_drawer_type)(grs_bitmap *bm,int nv,g3s_point **vertlist); typedef void (*flat_drawer_type)(int nv,int *vertlist); typedef int (*line_drawer_type)(fix x0,fix y0,fix x1,fix y1); void g3_set_special_render(tmap_drawer_type tmap_drawer,flat_drawer_type flat_drawer,line_drawer_type line_drawer); //Object functions: //gives the interpreter an array of points to use void g3_set_interp_points(g3s_point *pointlist); //calls the object interpreter to render an object. The object renderer //is really a seperate pipeline. returns true if drew bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb light,fix *glow_values); //init code for bitmap models void g3_init_polygon_model(void *model_ptr); //alternate interpreter for morphing object bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb light,vms_vector *new_points); // check a polymodel for it's color and return it int g3_poly_get_color(void *model_ptr); // routine to convert little to big endian in polygon model data void swap_polygon_model_data(ubyte *data); #endif dxx-rebirth-0.58.1-d1x/include/args.h000066400000000000000000000043571217717257200173130ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes for accessing arguments. * */ #ifndef _ARGS_H #define _ARGS_H #include "pstypes.h" extern int Num_args; extern char *Args[]; extern void InitArgs(int argc, char **argv); extern void args_exit(); // Struct that keeps all variables used by FindArg // Sys - System Options // Ctl - Control Options // Snd - Sound Options // Gfx - Graphics Options // Ogl - OpenGL Options // Mpl - Multiplayer Options // Edi - Editor Options // Dbg - Debugging/Undocumented Options typedef struct Arg { int SysShowCmdHelp; int SysUseNiceFPS; int SysMaxFPS; char *SysHogDir; int SysNoHogDir; int SysUsePlayersDir; int SysLowMem; char *SysPilot; int SysWindow; int SysNoBorders; int SysAutoDemo; int SysNoTitles; int CtlNoCursor; int CtlNoMouse; int CtlNoJoystick; int CtlNoStickyKeys; int SndNoSound; int SndNoMusic; int SndDisableSdlMixer; int GfxHiresFNTAvailable; #ifdef OGL int OglFixedFont; #endif int EdiNoBm; const char *MplUdpHostAddr; int MplUdpHostPort; int MplUdpMyPort; #ifdef USE_TRACKER const char *MplTrackerAddr; int MplTrackerPort; #endif int DbgVerbose; int DbgSafelog; int DbgNoRun; int DbgRenderStats; char *DbgAltTex; char *DbgTexMap; int DbgShowMemInfo; int DbgUseDoubleBuffer; int DbgBigPig; int DbgBpp; #ifdef OGL int DbgAltTexMerge; int DbgGlIntensity4Ok; int DbgGlLuminance4Alpha4Ok; int DbgGlRGBA2Ok; int DbgGlReadPixelsOk; int DbgGlGetTexLevelParamOk; #else int DbgSdlHWSurface; int DbgSdlASyncBlit; #endif } __pack__ Arg; extern struct Arg GameArg; #endif dxx-rebirth-0.58.1-d1x/include/byteswap.h000066400000000000000000000073361217717257200202150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * code to swap bytes because of big/little endian problems. * contains the macros: * SWAP{INT64,INT,SHORT}(x): returns a swapped version of x * INTEL_{INT64,INT,SHORT}(x): returns x after conversion to/from little endian * GET_INTEL_{INT64,INT,SHORT}(src): gets value from little-endian buffer src * PUT_INTEL_{INT64,INT,SHORT}(dest, src): puts src into little-endian buffer dest * * the GET/PUT macros are safe to use on platforms which segfault on unaligned word access * */ #ifndef _BYTESWAP_H #define _BYTESWAP_H #include // for memcpy #include "pstypes.h" #define SWAPSHORT(x) (((ubyte)(x) << 8) | (((ushort)(x)) >> 8)) #define SWAPINT(x) (((x)<<24) | (((uint)(x)) >> 24) | (((x) &0x0000ff00) << 8) | (((x) & 0x00ff0000) >> 8)) #ifndef macintosh #define SWAPINT64(x) ((((x) & 0xff00000000000000LL) >> 56) | (((x) & 0x00ff000000000000LL) >> 40) | (((x) & 0x0000ff0000000000LL) >> 24) | (((x) & 0x000000ff00000000LL) >> 8) | (((x) & 0x00000000ff000000LL) << 8) | (((x) & 0x0000000000ff0000LL) << 24) | (((x) & 0x000000000000ff00LL) << 40) | (((x) & 0x00000000000000ffLL) << 56)) #else #define SWAPINT64(x) ((((x) & 0xff00000000000000LL)/(2^56)) | (((x) & 0x00ff000000000000LL)/(2^40)) | (((x) & 0x0000ff0000000000LL)/(2^24)) | (((x) & 0x000000ff00000000LL)/(2^8)) | (((x) & 0x00000000ff000000LL)*(2^8)) | (((x) & 0x0000000000ff0000LL)*(2^24)) | (((x) & 0x000000000000ff00LL)*(2^40)) | (((x) & 0x00000000000000ffLL)*(2^56))) #endif #ifndef WORDS_BIGENDIAN #define INTEL_INT64(x) x #define INTEL_INT(x) x #define INTEL_SHORT(x) x #else // ! WORDS_BIGENDIAN #define INTEL_INT64(x) SWAPINT64(x) #define INTEL_INT(x) SWAPINT(x) #define INTEL_SHORT(x) SWAPSHORT(x) #endif // ! WORDS_BIGENDIAN #ifndef WORDS_NEED_ALIGNMENT #define GET_INTEL_INT64(s) INTEL_INT64(*(const u_int64_t *)(s)) #define GET_INTEL_INT(s) INTEL_INT(*(const uint *)(s)) #define GET_INTEL_SHORT(s) INTEL_SHORT(*(const ushort *)(s)) #define PUT_INTEL_INT64(d, s) { *(u_int64_t *)(d) = INTEL_INT64((u_int64_t)(s)); } #define PUT_INTEL_INT(d, s) { *(uint *)(d) = INTEL_INT((uint)(s)); } #define PUT_INTEL_SHORT(d, s) { *(ushort *)(d) = INTEL_SHORT((ushort)(s)); } #else // ! WORDS_NEED_ALIGNMENT static inline u_int64_t GET_INTEL_INT64(const void *s) { u_int64_t tmp; memcpy((void *)&tmp, s, 8); return INTEL_INT64(tmp); } static inline uint GET_INTEL_INT(const void *s) { uint tmp; memcpy((void *)&tmp, s, 4); return INTEL_INT(tmp); } static inline ushort GET_INTEL_SHORT(const void *s) { ushort tmp; memcpy((void *)&tmp, s, 2); return INTEL_SHORT(tmp); } #define PUT_INTEL_INT64(d, s) { uint tmp = INTEL_INT64(s); \ memcpy((void *)(d), (void *)&tmp, 8); } #define PUT_INTEL_INT(d, s) { uint tmp = INTEL_INT(s); \ memcpy((void *)(d), (void *)&tmp, 4); } #define PUT_INTEL_SHORT(d, s) { ushort tmp = INTEL_SHORT(s); \ memcpy((void *)(d), (void *)&tmp, 2); } #endif // ! WORDS_NEED_ALIGNMENT #endif // ! _BYTESWAP_H dxx-rebirth-0.58.1-d1x/include/console.h000066400000000000000000000013271217717257200200130ustar00rootroot00000000000000/* Console */ #ifndef _CONSOLE_H_ #define _CONSOLE_H_ #include "pstypes.h" /* Priority levels */ #define CON_CRITICAL -3 #define CON_URGENT -2 #define CON_HUD -1 #define CON_NORMAL 0 #define CON_VERBOSE 1 #define CON_DEBUG 2 #define CON_LINES_ONSCREEN 18 #define CON_SCROLL_OFFSET (CON_LINES_ONSCREEN - 3) #define CON_LINES_MAX 128 #define CON_LINE_LENGTH 2048 #define CON_STATE_OPEN 2 #define CON_STATE_OPENING 1 #define CON_STATE_CLOSING -1 #define CON_STATE_CLOSED -2 typedef struct console_buffer { char line[CON_LINE_LENGTH]; int priority; } __pack__ console_buffer; void con_init(void); void con_printf(int level, const char *fmt, ...); void con_showup(void); #endif /* _CONSOLE_H_ */ dxx-rebirth-0.58.1-d1x/include/dl_list.h000066400000000000000000000011651217717257200200030ustar00rootroot00000000000000/* * Doubly-linked list implementation * MD 2211 , 2007 */ #ifndef __DL_LIST__ #define __DL_LIST__ struct dl_list_elem { void *data; struct dl_list_elem *prev; struct dl_list_elem *next; }; typedef struct dl_list_elem dl_item; typedef struct { struct dl_list_elem *first; struct dl_list_elem *last; struct dl_list_elem *current; unsigned int size; } dl_list; dl_list *dl_init(); void dl_add(dl_list *, void *); void dl_remove(dl_list *, dl_item *); int dl_is_empty(dl_list const *); int dl_size(dl_list const *); int dl_forward(dl_list *); int dl_backward(dl_list *); #endif dxx-rebirth-0.58.1-d1x/include/dxxerror.h000066400000000000000000000036311217717257200202260ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for error handling/printing/exiting code * */ #ifndef _ERROR_H #define _ERROR_H #include #include #ifdef __GNUC__ #define __noreturn __attribute__ ((noreturn)) #define __attribute_gcc_format(X) __attribute__ ((format X)) #else #define __noreturn #define __attribute_gcc_format(X) #endif void warn_printf(char *s); int error_init(void (*func)(const char *)); //init error system, returns 0=ok void Warning(char *fmt,...); //print out warning message to user void set_warn_func(void (*f)(char *s));//specifies the function to call with warning messages void clear_warn_func(void (*f)(char *s));//say this function no longer valid void Error(const char *fmt,...) __noreturn __attribute_gcc_format((printf, 1, 2)); //exit with error code=1, print message #define Assert assert #ifndef NDEBUG //macros for debugging # if defined(__APPLE__) || defined(macintosh) extern void Debugger(void); // Avoids some name clashes # define Int3 Debugger # else # define Int3() ((void)0) # endif // Macintosh #else //macros for real game //Changed Assert and Int3 because I couldn't get the macros to compile -KRB #define Int3() ((void)0) #endif #endif /* _ERROR_H */ dxx-rebirth-0.58.1-d1x/include/editor/000077500000000000000000000000001217717257200174635ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/include/editor/centers.h000066400000000000000000000017641217717257200213070ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Center header * */ #ifndef _CENTERS_H #define _CENTERS_H #define CENTER_STRING_LENGTH 12 #include "fuelcen.h" extern char Center_names[MAX_CENTER_TYPES][CENTER_STRING_LENGTH]; void close_centers_window(); void do_centers_window(); #endif dxx-rebirth-0.58.1-d1x/include/editor/editor.h000066400000000000000000000573231217717257200211340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for editor functions, data strcutures, etc. * */ #ifndef _EDITOR_H #define _EDITOR_H #include "vecmat.h" #include "inferno.h" #include "gr.h" #include "ui.h" struct window; struct segment; /* * Constants * */ #define ORTHO_VIEWS 0 // set to 1 to enable 3 orthogonal views #define ED_SCREEN_W 800 //width of editor screen #define ED_SCREEN_H 600 //height of editor screen #define MENUBAR_H 16 #define GAMEVIEW_X 1 //where the 320x200 game window goes #define GAMEVIEW_Y 1+MENUBAR_H #define GAMEVIEW_W 320 #define GAMEVIEW_H 200 #define STATUS_X 0 #define STATUS_H 18 #define STATUS_Y (ED_SCREEN_H-STATUS_H) #define STATUS_W ED_SCREEN_W #define LVIEW_X 1 //large view #define LVIEW_Y (GAMEVIEW_Y+GAMEVIEW_H+2) #define LVIEW_W 447 #define LVIEW_H (STATUS_Y-LVIEW_Y-2) #define TMAPBOX_X (LVIEW_X+LVIEW_W+4) //location of first one #define TMAPBOX_Y (LVIEW_Y+2) #define TMAPBOX_W 64 #define TMAPBOX_H 64 #define TMAPCURBOX_X (TMAPBOX_X + 4*(TMAPBOX_W + 3)) #define TMAPCURBOX_Y (TMAPBOX_Y + TMAPBOX_H) #define OBJCURBOX_X (TMAPCURBOX_X) #define OBJCURBOX_Y (TMAPCURBOX_Y + 3*(TMAPBOX_H + 2) -40) #define PAD_X (GAMEVIEW_X + GAMEVIEW_W + 16) #define PAD_Y (GAMEVIEW_Y + 4) #define SMALLVIEW_W 173 //width of small view windows #define SMALLVIEW_H 148 //height of small view windows #define TVIEW_X (LVIEW_X+LVIEW_W+2) //top view #define TVIEW_Y LVIEW_Y #define TVIEW_W SMALLVIEW_W #define TVIEW_H SMALLVIEW_H #define FVIEW_X TVIEW_X //front view #define FVIEW_Y (TVIEW_Y+SMALLVIEW_H+2) #define FVIEW_W SMALLVIEW_W #define FVIEW_H SMALLVIEW_H #define RVIEW_X (TVIEW_X+SMALLVIEW_W+2) //right view #define RVIEW_Y FVIEW_Y #define RVIEW_W SMALLVIEW_W #define RVIEW_H SMALLVIEW_H #define GVIEW_X RVIEW_X //group view #define GVIEW_Y TVIEW_Y #define GVIEW_W SMALLVIEW_W #define GVIEW_H SMALLVIEW_H //there were color constants here, but I moved them to meddraw.c - Matt #define SEGMOVE_PAD_ID 0 #define SEGSIZE_PAD_ID 1 #define CURVE_PAD_ID 2 #define TEXTURE_PAD_ID 3 #define OBJECT_PAD_ID 4 #define OBJMOV_PAD_ID 5 #define GROUP_PAD_ID 6 #define LIGHTING_PAD_ID 7 #define TEST_PAD_ID 8 #define MAX_PAD_ID 8 /* * Strucures * */ #define VF_ANGLES 0 #define VF_MATRIX 1 // Default size of a segment #define DEFAULT_X_SIZE F1_0*20 #define DEFAULT_Y_SIZE F1_0*20 #define DEFAULT_Z_SIZE F1_0*20 // Scale factor from 3d units (integer portion) to uv coordinates (integer portion) #define VMAG (F1_0 / (DEFAULT_X_SIZE/F1_0)) #define UMAG VMAG // unused // Number of segments which can be found (size of Found_segs[]) #define MAX_FOUND_SEGS 200 #define MAX_SELECTED_SEGS (MAX_SEGMENTS) #define MAX_WARNING_SEGS (MAX_SEGMENTS) #define MAX_GROUPS 10 #define ROT_GROUP MAX_GROUPS // Modes for segment sizing #define SEGSIZEMODE_FREE 1 #define SEGSIZEMODE_ALL 2 #define SEGSIZEMODE_CURSIDE 3 #define SEGSIZEMODE_EDGE 4 #define SEGSIZEMODE_VERTEX 5 #define SEGSIZEMODE_MIN SEGSIZEMODE_FREE #define SEGSIZEMODE_MAX SEGSIZEMODE_VERTEX //defines a view for an editor window typedef struct editor_view { short ev_num; //each view has it's own number short ev_changed; //set to true if view changed grs_canvas *ev_canv; //points to this window's canvas fix ev_dist; //the distance from the view point vms_matrix ev_matrix; //the view matrix fix ev_zoom; //zoom for this window } editor_view; /* * Global variables * */ extern editor_view *Views[]; extern int N_views; extern int Large_view_index; extern UI_GADGET_USERBOX * LargeViewBox; extern int Found_seg_index; // Index in Found_segs corresponding to Cursegp extern int gamestate_not_restored; extern grs_font *editor_font; extern vms_vector Ed_view_target; // what editor is looking at extern struct window *Pad_info; // Keypad text extern int Show_axes_flag; // 0 = don't show, !0 = do show coordinate axes in *Cursegp orientation extern int Autosave_count; // Current counter for which autosave mine we are "on" extern int Autosave_flag; // Whether or not Autosave is on. extern struct tm Editor_time_of_day; extern int SegSizeMode; // Mode = 0/1 = not/is legal to move bound vertices, void init_editor(void); void close_editor(void); // Initialize all vertices to inactive status. extern void init_all_vertices(void); // Returns true if vertex vi is contained in exactly one segment, else returns false. extern int is_free_vertex(int vi); // Set existing vertex vnum to value *vp. extern int med_set_vertex(int vnum,vms_vector *vp); extern void med_combine_duplicate_vertices(sbyte *vlp); // Attach side newside of newseg to side destside of destseg. // Copies *newseg into global array Segments, increments Num_segments. // Forms a weld between the two segments by making the new segment fit to the old segment. // Updates number of faces per side if necessitated by new vertex coordinates. // Return value: // 0 = successful attach // 1 = No room in Segments[]. // 2 = No room in Vertices[]. extern int med_attach_segment(struct segment *destseg, struct segment *newseg, int destside, int newside); // Delete a segment. // Deletes a segment from the global array Segments. // Updates Cursegp to be the segment to which the deleted segment was connected. If there is // more than one connected segment, the new Cursegp will be the segment with the highest index // of connection in the deleted segment (highest index = front) // Return value: // 0 = successful deletion // 1 = unable to delete extern int med_delete_segment(struct segment *sp); // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively // modifying its four free vertices in the global array Vertices. // It is illegal to rotate a segment which has MAX_SIDES_PER_SEGMENT != 1. // Pitch, bank, heading are about the point which is the average of the four points // forming the side of connection. // Return value: // 0 = successful rotation // 1 = MAX_SIDES_PER_SEGMENT makes rotation illegal (connected to 0 or 2+ segments) // 2 = Rotation causes degeneracy, such as self-intersecting segment. extern int med_rotate_segment(struct segment *seg, vms_matrix *rotmat); extern int med_rotate_segment_ang(struct segment *seg, vms_angvec *ang); // Scales a segment, destructively modifying vertex coordinates in global Vertices[]. // Uses scale factor in sp->scale. // Modifies only free vertices (those which are not part of a segment other than *sp). // The vector *svp contains the x,y,z scale factors. The x,y,z directions are relative // to the segment. x scales in the dimension of the right vector, y of the up vector, z of the forward vector. // The dimension of the vectors is determined by averaging appropriate sets of 4 of the 8 points. extern void med_scale_segment(struct segment *sp); // Create a wall which can be removed. // Creates wall at sp->sides[side], making it part of segment sp // Removable walls must be placed between two connected segments. You should add the removable // wall on both sides. In fact, you really must. extern void create_removable_wall(struct segment *sp, int side, int tmap_num); // Loads mine *name from disk, updating global variables: // Segments, Vertices // Num_segments,Num_vertices // Cursegp = pointer to active segment. Written as an index in med_save_mine, converted to a pointer // at load time. // Returns: // 0 = successfully loaded. // 1 = unable to load. extern int med_load_mine(char *name); // Loads game *name from disk. // This function automatically loads mine with name.MIN extern int med_load_game(char *name); // Loads a previous generation mine. Needs to be updated in code. extern int med_load_pmine(char *name); // Saves mine contained in Segments[] and Vertices[]. // Num_segments = number of segments in mine. // Num_vertices = number of vertices in mine. // Cursegp = current segment. // Saves Num_segments, and index of current segment (which is Cursegp - Segments), which will be converted to a pointer // and written to Cursegp in med_load_mine. // Returns: // 0 = successfully saved. // 1 = unable to save. extern int med_save_mine(char *name); // Loads group *filename from disk. // Adds group to global Segments and Vertices array. // Returns: // 0 = successfully loaded. // 1 = unable to load. extern int med_load_group( char *filename, int *vertex_ids, short *segment_ids, int *num_vertices, int *num_segments); // Saves group *filename from disk. // Saves group defined by vertex_ids and segment_ids to disk. // Returns: // 0 = successfully saved. // 1 = unable to save. extern int med_save_group( char *filename, int *vertex_ids, short *segment_ids, int num_vertices, int num_segments); // Updates the screen... (I put the prototype here for curves.c) extern int medlisp_update_screen(); // Returns 0 if no error, 1 if error, whatever that might be. // Sets globals: // Num_segments // Num_vertices // Cursegp = pointer to only segment. extern int create_new_mine(void); // extern void med_create_segment(segment *sp, vms_vector *scale); extern void old_med_attach_segment(struct segment *sp,int main_side,int branch_side,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp); // Copy a segment from *ssp to *dsp. Do not simply copy the struct. Use *dsp's vertices, copying in // just the values, not the indices. extern void med_copy_segment(struct segment *dsp,struct segment *ssp); // Create a segment given center, dimensions, rotation matrix. // Note that the created segment will always have planar sides and rectangular cross sections. // It will be created with walls on all sides, ie not connected to anything. void med_create_segment(struct segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp); // Create a default segment. // Useful for when user creates a garbage segment. extern void med_create_default_segment(struct segment *sp); // Create New_segment with sizes found in *scale. extern void med_create_new_segment(vms_vector *scale); // Create New_segment with sizes found in Cursegp. extern void med_create_new_segment_from_cursegp(void); // Update New_segment using scale factors. extern void med_update_new_segment(void); // Replace *sp with New_segment. extern void med_update_segment(struct segment *sp); // Create a new segment and use it to form a bridge between two existing segments. // Specify two segment:side pairs. If either segment:side is not open (ie, segment->children[side] != -1) // then it is not legal to form the brider. // Return: // 0 bridge segment formed // 1 unable to form bridge because one (or both) of the sides is not open. // Note that no new vertices are created by this process. extern int med_form_bridge_segment(struct segment *seg1, int side1, struct segment *seg2, int side2); // Compress mine at Segments and Vertices by squeezing out all holes. // If no holes (ie, an unused segment followed by a used segment), then no action. // If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then // they are properly updated. extern void med_compress_mine(void); // Extract the forward vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the front face of the segment // to the center of the back face of the segment. extern void med_extract_forward_vector_from_segment(struct segment *sp,vms_vector *vp); // Extract the right vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the left face of the segment // to the center of the right face of the segment. extern void med_extract_right_vector_from_segment(struct segment *sp,vms_vector *vp); // Extract the up vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the bottom face of the segment // to the center of the top face of the segment. extern void med_extract_up_vector_from_segment(struct segment *sp,vms_vector *vp); // Compute the center point of a side of a segment. // The center point is defined to be the average of the 4 points defining the side. extern void med_compute_center_point_on_side(vms_vector *vp,struct segment *sp,int side); extern void set_matrix_based_on_side(vms_matrix *rotmat,int destside); // Given a forward vector, compute and return an angvec triple. // [ THIS SHOULD BE MOVED TO THE VECTOR MATRIX LIBRARY ] extern vms_angvec *vm_vec_to_angles(vms_angvec *result, vms_vector *forvec); // Curves stuff. #define ACCURACY 0.1*F1_0 typedef struct vms_equation { union { struct {fix x3, x2, x1, x0, y3, y2, y1, y0, z3, z2, z1, z0;} n; fix xyz[3][4]; }; } vms_equation; extern void create_curve(vms_vector *p1, vms_vector *p4, vms_vector *r1, vms_vector *r4, vms_equation *coeffs); // Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t^3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4 extern vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t); extern fix curve_dist(vms_equation *coeffs, int degree, fix t0, vms_vector *p0, fix dist); extern void curve_dir(vms_equation *coeffs, int degree, fix t0, vms_vector *dir); extern void plot_parametric(vms_equation *coeffs, fix min_t, fix max_t, fix del_t); // Curve generation routine. // Returns 1 if curve is generated. // Returns 0 if no curve. extern int generate_curve( fix r1scale, fix r4scale ); // Deletes existing curve generated in generate_curve(). extern void delete_curve(); // --- // -- Temporary function, identical to med_rotate_segment, but it takes a vector instead of an angvec // --- extern int med_rotate_segment_vec(segment *seg, vms_vector *vec); extern void med_extract_matrix_from_segment(struct segment *sp,vms_matrix *rotmat); // Assign default u,v coordinates to all sides of a segment. // This routine should only be used for segments which are not connected to anything else, // ie the segment created at mine creation. extern void assign_default_uvs_to_segment(struct segment *segp); extern void assign_default_uvs_to_side(struct segment *segp, int side); extern void assign_default_uvs_to_side(struct segment *segp,int side); // Assign u,v coordinates to con_seg, con_common_side from base_seg, base_common_side // They are connected at the edge defined by the vertices abs_id1, abs_id2. extern void med_assign_uvs_to_side(struct segment *con_seg, int con_common_side, struct segment *base_seg, int base_common_side, int abs_id1, int abs_id2); // Debug -- show a matrix. // type: 1 --> printf // *s = string to display // *mp = matrix to display extern void show_matrix(char *s,vms_matrix *mp,int type); // Create coordinate axes in orientation of specified segment, stores vertices at *vp. extern void create_coordinate_axes_from_segment(struct segment *sp,int *vertnums); // Scale a segment. Then, if it is connected to something, rotate it. extern int med_scale_and_rotate_segment(struct segment *seg, vms_angvec *rot); // Set Vertex_active to number of occurrences of each vertex. // Set Num_vertices. extern void set_vertex_counts(void); // Modify seg2 to share side2 with seg1:side1. This forms a connection between // two segments without creating a new segment. It modifies seg2 by sharing // vertices from seg1. seg1 is not modified. Four vertices from seg2 are // deleted. // If the four vertices forming side2 in seg2 are not free, the joint is not formed. // Return code: // 0 joint formed // 1 unable to form joint because one or more vertices of side2 is not free // 2 unable to form joint because side1 is already used extern int med_form_joint(struct segment *seg1, int side1, struct segment *seg2, int side2); // The current texture... use by saying something=bm_lock_bitmap(CurrentTexture) extern int CurrentTexture; extern void compute_segment_center(vms_vector *vp,struct segment *sp); extern void med_propagate_tmaps_to_segments(struct segment *base_seg,struct segment *con_seg, int uv_only_flag); extern void med_propagate_tmaps_to_back_side(struct segment *base_seg, int back_side, int uv_only_flag); extern void med_propagate_tmaps_to_any_side(struct segment *base_seg, int back_side, int tmap_num, int uv_only_flag); // Find segment adjacent to sp:side. // Adjacent means a segment which shares all four vertices. // Return true if segment found and fill in segment in adj_sp and side in adj_side. // Return false if unable to find, in which case adj_sp and adj_side are undefined. extern int med_find_adjacent_segment_side(struct segment *sp, int side, struct segment **adj_sp, int *adj_side); // Finds the closest segment and side to sp:side. extern int med_find_closest_threshold_segment_side(struct segment *sp, int side, struct segment **adj_sp, int *adj_side, fix threshold); // Given two segments, return the side index in the connecting segment which connects to the base segment extern int find_connect_side(struct segment *base_seg, struct segment *con_seg); // Select previous segment. // If there is a connection on the side opposite to the current side, then choose that segment. // If there is no connecting segment on the opposite face, try any segment. extern void get_previous_segment(int curseg_num, int curside,int *newseg_num, int *newside); // Select next segment. // If there is a connection on the current side, then choose that segment. // If there is no connecting segment on the current side, try any segment. extern void get_next_segment(int curseg_num, int curside, int *newseg_num, int *newside); // Copy texture maps in newseg to nsp. extern void copy_uvs_seg_to_seg(struct segment *nsp,struct segment *newseg); // Return true if segment is concave. extern int check_seg_concavity(struct segment *s); // Return N_found_segs = number of concave segments in mine. // Segment ids stored at Found_segs extern void find_concave_segs(void); // High level call. Check for concave segments, print warning message (using editor_status) // if any concave segments. // Calls find_concave_segs, therefore N_found_segs gets set, and Found_segs filled in. extern void warn_if_concave_segments(void); // Warn if segment s is concave. extern void warn_if_concave_segment(struct segment *s); // Add a vertex to the vertex list. extern int med_add_vertex(vms_vector *vp); // Add a vertex to the vertex list which may be identical to another vertex (in terms of coordinates). // Don't scan list, looking for presence of a vertex with same coords, add this one. extern int med_create_duplicate_vertex(vms_vector *vp); // Create a new segment, duplicating exactly, including vertex ids and children, the passed segment. extern int med_create_duplicate_segment(struct segment *sp); // Returns the index of a free segment. // Scans the Segments array. extern int get_free_segment_number(void); // Diagnostic message. #define diagnostic_message editor_status #define diagnostic_message_fmt editor_status_fmt // Status Icon. extern void print_status_icon( char icon[1], int position ); extern void clear_status_icon( char icon[1], int position ); // Editor status message. extern void editor_status_fmt(const char *format, ... ); // Variables in editor.c that the k*.c files need #define UF_NONE 0x000 //nothing has changed #define UF_WORLD_CHANGED 0x001 //something added or deleted #define UF_VIEWPOINT_MOVED 0x002 //what we're watching has moved #define UF_GAME_VIEW_CHANGED 0x004 //the game window changed #define UF_ED_STATE_CHANGED 0x008 //something like curside,curseg changed #define UF_ALL 0xffffffff //all flags extern uint Update_flags; extern int Funky_chase_mode; extern vms_angvec Seg_orientation; extern vms_vector Seg_scale; extern int mine_changed; extern int ModeFlag; extern editor_view *current_view; //the view for the different windows extern editor_view LargeView; extern editor_view TopView; extern editor_view FrontView; extern editor_view RightView; extern void set_view_target_from_segment(struct segment *sp); extern int SafetyCheck(); void editor_status( const char *text); extern int MacroNumEvents; extern int MacroStatus; //extern int Highest_vertex_index; // Highest index in Vertices and Vertex_active, an efficiency hack //extern int Highest_segment_index; // Highest index in Segments, an efficiency hack extern int Lock_view_to_cursegp; // !0 means whenever cursegp changes, view it // eglobal.c extern int Num_tilings; // number of tilings/wall extern int Degenerate_segment_found; extern sbyte Been_visited[]; // List of segments visited in a recursive search, if element n set, segment n done been visited // Initializes autosave system. // Sets global Autosave_count to 0. extern void init_autosave(void); // Closes autosave system. // Deletes all autosaved files. extern void close_autosave(void); // Saves current mine to name.miX where name = suffix of mine name and X = Autosave_count. // For example, if name = "cookie.min", and Autosave_count = 3, then writes "cookie.mi3". // Increments Autosave_count, wrapping from 9 to 0. // (If there is no current mine name, assume "temp.min") // Call med_save_mine to save the mine. extern void autosave_mine(char *name); // Timed autosave extern void TimedAutosave(char *name); extern void set_editor_time_of_day(); // Undo function extern int undo(void); extern char mine_filename[PATH_MAX]; extern char undo_status[10][100]; // group.c int AttachSegmentNewAng(vms_angvec *pbh); int RotateSegmentNew(vms_angvec *pbh); int rotate_segment_new(vms_angvec *pbh); //get & free vertices int alloc_vert(); void free_vert(int vert_num); // The current object type and id declared in eglobal.c extern short Cur_object_type; extern short Cur_object_id; // From med.c extern int DisplayCurrentRobotType(void); extern short Cur_object_index; extern int render_3d_in_big_window; extern void move_object_to_mouse_click(void); //these are instances of canvases, pointed to by variables below extern grs_canvas _canv_editor_game; //the game on the editor screen //these are pointers to our canvases extern grs_canvas *Canv_editor; //the editor screen extern grs_canvas *Canv_editor_game; //the game on the editor screen extern struct window *Pad_info; // Keypad text //where the editor is looking extern vms_vector Ed_view_target; extern int gamestate_not_restored; extern UI_DIALOG * EditorWindow; extern int Large_view_index; extern UI_GADGET_USERBOX * GameViewBox; extern UI_GADGET_USERBOX * LargeViewBox; extern UI_GADGET_USERBOX * GroupViewBox; extern void med_point_2_vec(grs_canvas *canv,vms_vector *v,short sx,short sy); //shutdown ui on the editor screen void close_editor_screen(void); // From eobject.c extern int place_object(struct segment *segp, vms_vector *object_pos, short object_type, short object_id); // from ksegsize.c extern void med_extract_up_vector_from_segment_side(struct segment *sp, int sidenum, vms_vector *vp); extern void med_extract_right_vector_from_segment_side(struct segment *sp, int sidenum, vms_vector *vp); extern void med_extract_forward_vector_from_segment_side(struct segment *sp, int sidenum, vms_vector *vp); // In medmisc.c extern void draw_world_from_game(void); // In medrobot.c extern void close_all_windows(void); // In seguvs.c // Amount to stretch a texture map by. // The two different ones are for the two dimensions of a texture map. extern fix Stretch_scale_x, Stretch_scale_y; #endif dxx-rebirth-0.58.1-d1x/include/editor/ehostage.h000066400000000000000000000016061217717257200214360ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * . * */ #ifndef _EHOSTAGE_H #define _EHOSTAGE_H extern int do_hostage_dialog(); extern void hostage_close_window(); extern void do_hostage_window(); #endif dxx-rebirth-0.58.1-d1x/include/editor/eobject.h000066400000000000000000000021251217717257200212470ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for eobject.c * */ #ifndef _EOBJECT_H #define _EOBJECT_H int ObjectSelectNextInMine(void); int ObjectSelectPrevInMine(void); int ObjectDecreaseBankBig(); int ObjectIncreaseBankBig(); int ObjectDecreasePitchBig(); int ObjectIncreasePitchBig(); int ObjectDecreaseHeadingBig(); int ObjectIncreaseHeadingBig(); int ObjectFlipObject(); #endif dxx-rebirth-0.58.1-d1x/include/editor/esegment.h000066400000000000000000000071041217717257200214450ustar00rootroot00000000000000#pragma once #include "segment.h" extern segment *Cursegp; // Pointer to current segment in the mine, the one to which things happen. extern segment New_segment; // The segment which can be added to the mine. extern int Curside; // Side index in 0..MAX_SIDES_PER_SEGMENT of active side. extern int Curedge; // Current edge on current side, in 0..3 extern int Curvert; // Current vertex on current side, in 0..3 extern int AttachSide; // Side on segment to attach extern int Draw_all_segments; // Set to 1 means draw_world draws all segments in Segments, else draw only connected segments extern segment *Markedsegp; // Marked segment, used in conjunction with *Cursegp to form joints. extern int Markedside; // Marked side on Markedsegp. extern sbyte Vertex_active[MAX_VERTICES]; // !0 means vertex is in use, 0 means not in use. // The extra group in the following arrays is used for group rotation. extern group GroupList[MAX_GROUPS+1]; extern segment *Groupsegp[MAX_GROUPS+1]; extern int Groupside[MAX_GROUPS+1]; extern int current_group; extern int num_groups; extern int Current_group; extern short Found_segs[]; // List of segment numbers "found" under cursor click extern int N_found_segs; // Number of segments found at Found_segs extern int N_selected_segs; // Number of segments found at Selected_segs extern short Selected_segs[]; // List of segment numbers currently selected extern int N_warning_segs; // Number of segments warning-worthy, such as a concave segment extern short Warning_segs[]; // List of warning-worthy segments extern int Groupside[MAX_GROUPS+1]; extern int current_group; extern int num_groups; extern int Current_group; // Returns true if vertex vi is contained in exactly one segment, else returns false. extern int is_free_vertex(int vi); // Set existing vertex vnum to value *vp. extern int med_set_vertex(int vnum,vms_vector *vp); extern void med_combine_duplicate_vertices(sbyte *vlp); // Attach side newside of newseg to side destside of destseg. // Copies *newseg into global array Segments, increments Num_segments. // Forms a weld between the two segments by making the new segment fit to the old segment. // Updates number of faces per side if necessitated by new vertex coordinates. // Return value: // 0 = successful attach // 1 = No room in Segments[]. // 2 = No room in Vertices[]. extern int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside); // Delete a segment. // Deletes a segment from the global array Segments. // Updates Cursegp to be the segment to which the deleted segment was connected. If there is // more than one connected segment, the new Cursegp will be the segment with the highest index // of connection in the deleted segment (highest index = front) // Return value: // 0 = successful deletion // 1 = unable to delete extern int med_delete_segment(segment *sp); // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively // modifying its four free vertices in the global array Vertices. // It is illegal to rotate a segment which has MAX_SIDES_PER_SEGMENT != 1. // Pitch, bank, heading are about the point which is the average of the four points // forming the side of connection. // Return value: // 0 = successful rotation // 1 = MAX_SIDES_PER_SEGMENT makes rotation illegal (connected to 0 or 2+ segments) // 2 = Rotation causes degeneracy, such as self-intersecting segment. extern int med_rotate_segment(segment *seg, vms_matrix *rotmat); extern int med_rotate_segment_ang(segment *seg, vms_angvec *ang); dxx-rebirth-0.58.1-d1x/include/editor/eswitch.h000066400000000000000000000021601217717257200213010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Headers for switch adding functions * */ #ifndef _ESWITCH_H #define _ESWITCH_H #include "inferno.h" #include "segment.h" #include "switch.h" extern int bind_wall_to_trigger(); extern int trigger_remove(); extern int remove_trigger(segment *seg, short side); extern int remove_trigger_num(int trigger_num); extern void close_trigger_window(); extern void do_trigger_window(); #endif dxx-rebirth-0.58.1-d1x/include/editor/info.h000066400000000000000000000015711217717257200205730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for info.c * */ #ifndef _INFO_H #define _INFO_H struct window; struct window *info_window_create(void); extern int init_info; #endif dxx-rebirth-0.58.1-d1x/include/editor/kdefs.h000066400000000000000000000174271217717257200207430ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ // In khelp.c int DoHelp(); // In kcurve.c int InitCurve(); int GenerateCurve(); int DecreaseR4(); int IncreaseR4(); int DecreaseR1(); int IncreaseR1(); int DeleteCurve(); int SetCurve(); // In kmine.c int SaveMine(); int LoadMine(); int MineMenu(); int CreateNewMine(); int LoadOldMine(); int SaveSituation(); int LoadSituation(); // In kgame.c int SetPlayerPosition(void); int SaveGameData(); int LoadGameData(); int LoadMineOnly(); void ResetFilename(); // In group.c int LoadGroup(); int SaveGroup(); int PrevGroup(); int NextGroup(); int CreateGroup(); int SubtractFromGroup(); int DeleteGroup(); int MarkGroupSegment(); int MoveGroup(void); int CopyGroup(void); int AttachSegmentNew(); int UngroupSegment(); int GroupSegment(); int Degroup(); int RotateGroup(); // In segment.c int ToggleBottom(); void make_curside_bottom_side(); // In editor.c int UndoCommand(); // In kview.c int ZoomOut(); int ZoomIn(); int MoveAway(); int MoveCloser(); int ToggleChaseMode(); // In kbuild.c int CreateBridge(); int FormJoint(); int CreateAdjacentJoint(); int CreateAdjacentJointsSegment(); int CreateAdjacentJointsAll(); int CreateSloppyAdjacentJoint(); int CreateSloppyAdjacentJointsGroup(); // In ksegmove.c int DecreaseHeading(); int IncreaseHeading(); int DecreasePitch(); int IncreasePitch(); int DecreaseBank(); int IncreaseBank(); // In ksegsel.c int SelectCurrentSegForward(); int SelectCurrentSegBackward(); int SelectNextSide(); int SelectPrevSide(); int CopySegToMarked(); int SelectBottom(); int SelectFront(); int SelectTop(); int SelectBack(); int SelectLeft(); int SelectRight(); // In ksegsize.c int IncreaseSegLength(); int DecreaseSegLength(); int DecreaseSegWidth(); int IncreaseSegWidth(); int IncreaseSegHeight(); int DecreaseSegHeight(); int ToggleSegSizeMode(); int PerturbCurside(); int PerturbCursideBig(); int IncreaseSegLengthBig(); int DecreaseSegLengthBig(); int DecreaseSegWidthBig(); int IncreaseSegWidthBig(); int IncreaseSegHeightBig(); int DecreaseSegHeightBig(); int IncreaseSegLengthDefault(); int DecreaseSegLengthDefault(); int IncreaseSegWidthDefault(); int DecreaseSegWidthDefault(); int IncreaseSegHeightDefault(); int DecreaseSegHeightDefault(); // In ktmap.c int AssignTexture(); int AssignTexture2(); int ClearTexture2(); int PropagateTextures(); int PropagateTexturesMove(); int PropagateTexturesMoveUVs(); int PropagateTexturesUVs(); int PropagateTexturesSelected(); //--//// In macro.c //--//int MacroMenu(); //--//int MacroPlayFast(); //--//int MacroPlayNormal(); //--//int MacroRecordAll(); //--//int MacroRecordKeys(); //--//int MacroSave(); //--//int MacroLoad(); // In editor.c int medlisp_update_screen(); int medlisp_delete_segment(void); int medlisp_scale_segment(void); int medlisp_rotate_segment(void); int medlisp_add_segment(); int AttachSegment(); int DeleteSegment(); int DosShell(); int CallLisp(); int ExitEditor(); int ShowAbout(); int ExchangeMarkandCurseg(); int med_keypad_goto_prev(); int med_keypad_goto_next(); int med_keypad_goto(); int med_increase_tilings(); int med_decrease_tilings(); int ToggleAutosave(); int MarkStart(); int MarkEnd(); // Texture.c int TexFlipX(); int TexFlipY(); int TexSlideUp(); int TexSlideLeft(); int TexSetDefault(); int TexSlideRight(); int TexRotateLeft(); int TexSlideDown(); int TexRotateRight(); int TexSelectActiveEdge(); int TexRotate90Degrees(); int TexIncreaseTiling(); int TexDecreaseTiling(); int TexSlideUpBig(); int TexSlideLeftBig(); int TexSlideRightBig(); int TexRotateLeftBig(); int TexSlideDownBig(); int TexRotateRightBig(); int TexStretchDown(); int TexStretchUp(); // object.c int ObjectPlaceObject(); int ObjectMakeCoop(); int ObjectPlaceObjectTmap(); int ObjectDelete(); int ObjectMoveForward(); int ObjectMoveLeft(); int ObjectSetDefault(); int ObjectMoveRight(); int ObjectMoveBack(); int ObjectMoveDown(); int ObjectMoveUp(); int ObjectMoveNearer(); int ObjectMoveFurther(); int ObjectSelectNextinSegment(); int ObjectSelectNextType(); int ObjectDecreaseBank(); int ObjectIncreaseBank(); int ObjectDecreasePitch(); int ObjectIncreasePitch(); int ObjectDecreaseHeading(); int ObjectIncreaseHeading(); int ObjectResetObject(); // elight.c int LightSelectNextVertex(); int LightSelectNextEdge(); int LightCopyIntensity(); int LightCopyIntensitySegment(); int LightDecreaseLightVertex(); int LightIncreaseLightVertex(); int LightDecreaseLightSide(); int LightIncreaseLightSide(); int LightDecreaseLightSegment(); int LightIncreaseLightSegment(); int LightSetMaximum(); int LightSetDefault(); int LightSetDefaultAll(); int LightAmbientLighting(); // seguvs.c int fix_bogus_uvs_on_side(); int fix_bogus_uvs_all(); int set_average_light_on_curside(void); int set_average_light_on_all(void); int set_average_light_on_all_quick(void); // Miscellaneous, please put in correct file if you have time int IncreaseDrawDepth(); int DecreaseDrawDepth(); int GotoMainMenu(); int GotoGameScreen(); int DropIntoDebugger(); int CreateDefaultNewSegment(); int CreateDefaultNewSegmentandAttach(); int ClearSelectedList(); int ClearFoundList(); int SortSelectedList(); int SetPlayerFromCurseg(); int SetPlayerFromCursegAndRotate(); int SetPlayerFromCursegMinusOne(); int FindConcaveSegs(); int SelectNextFoundSeg(); int SelectPreviousFoundSeg(void); int do_reset_orient(); int GameZoomOut(); int GameZoomIn(); // John's temp page stuff int medtmp_set_page(); // In objpage.c int objpage_goto_next_object(); // In medsel.c extern int SortSelectedList(void); extern int SelectNextFoundSeg(void); extern int SelectPreviousFoundSeg(void); // In wall.c extern int wall_add_blastable(void); extern int wall_add_door(void); extern int wall_add_closed_wall(void); extern int wall_add_external_wall(void); extern int wall_lock_door(void); extern int wall_unlock_door(void); extern int wall_automate_door(void); extern int wall_deautomate_door(void); extern int wall_add_illusion(void); extern int wall_remove(void); extern int wall_restore_all(void); extern int wall_assign_door_1(void); extern int wall_assign_door_2(void); extern int wall_assign_door_3(void); extern int wall_assign_door_4(void); extern int wall_assign_door_5(void); extern int wall_assign_door_6(void); extern int wall_assign_door_7(void); extern int wall_assign_door_8(void); extern int do_wall_dialog(void); extern int do_trigger_dialog(void); extern int check_walls(void); extern int delete_all_walls(void); // In centers.c extern int do_centers_dialog(void); // In switch.c //extern int trigger_add_damage(void); //extern int trigger_add_blank(void); //extern int trigger_add_exit(void); //extern int trigger_add_repair(void); //extern int trigger_control(void); //extern int trigger_remove(void); //extern int trigger_add_if_control_center_dead(void); extern int bind_wall_to_control_trigger(void); // In med.c extern int fuelcen_create_from_curseg(); extern int repaircen_create_from_curseg(); extern int controlcen_create_from_curseg(); extern int robotmaker_create_from_curseg(); extern int fuelcen_reset_all(); extern int RestoreGameState(); extern int fuelcen_delete_from_curseg(); // In editor\robot.c extern int do_robot_dialog(); extern int do_object_dialog(); // In editor\hostage.c extern int do_hostage_dialog(); dxx-rebirth-0.58.1-d1x/include/editor/kfuncs.h000066400000000000000000000015161217717257200211300ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for kfuncs.c * */ #ifndef _KFUNCS_H #define _KFUNCS_H void init_med_functions(void); #endif dxx-rebirth-0.58.1-d1x/include/editor/macro.h000066400000000000000000000015121217717257200207340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for macro.c * */ #ifndef _MACRO_H #define _MACRO_H void macro_free_buffer(void); #endif dxx-rebirth-0.58.1-d1x/include/editor/meddraw.h000066400000000000000000000023671217717257200212670ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Defnts for med drawing stuff * */ #ifndef _MEDDRAW_H #define _MEDDRAW_H void meddraw_init_views( grs_canvas * canvas); void draw_world(grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth); void find_segments(short x,short y,grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth); // segp = pointer to segments array, probably always Segments. // automap_flag = 1 if this render is for the automap, else 0 (for editor) extern void draw_mine_all(segment *segp, int automap_flag); #endif dxx-rebirth-0.58.1-d1x/include/editor/medlisp.h000066400000000000000000000020301217717257200212640ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #ifndef _MEDLISP_H #define _MEDLISP_H int medlisp_init(); void medlisp_go(); void medlisp_do_string( char * s, int length, int show_results ); void medlisp_close(); int medlisp_attach_function( char * LispFuncName, double (* Cfunction)(void), int NumArgs ); extern double medlisp_args[]; #endif dxx-rebirth-0.58.1-d1x/include/editor/medmisc.h000066400000000000000000000024631217717257200212620ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Defn'tns for medmisc.c * */ #ifndef _MEDMISC_H #define _MEDMISC_H void GetMouseRotation( int idx, int idy, vms_matrix * RotMat ); extern int Gameview_lockstep; //In medmisc.c int ToggleLockstep(); int medlisp_delete_segment(void); int medlisp_scale_segment(void); int medlisp_rotate_segment(void); int ToggleLockViewToCursegp(void); int ToggleDrawAllSegments(); int IncreaseDrawDepth(void); int DecreaseDrawDepth(void); int ToggleCoordAxes(); extern int Big_depth; void set_chase_matrix(segment *sp); void set_view_target_from_segment(segment *sp); #endif dxx-rebirth-0.58.1-d1x/include/editor/medrobot.h000066400000000000000000000016711217717257200214540ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for robot.c * */ #ifndef _MED_ROBOT_H #define _MED_ROBOT_H extern void robot_close_window(); extern void do_robot_window(); extern void object_close_window(); extern void do_object_window(); #endif dxx-rebirth-0.58.1-d1x/include/editor/medsel.h000066400000000000000000000016271217717257200211130ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * rountines stipped from med.c for segment selection * */ #ifndef _MEDSEL_H #define _MEDSEL_H extern void sort_seg_list(int n_segs,short *segnumlist,vms_vector *pos); #endif dxx-rebirth-0.58.1-d1x/include/editor/medwall.h000066400000000000000000000034441217717257200212660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Created from version 1.6 of main\wall.h * */ #ifndef _MEDWALL_H #define _MEDWALL_H #include "wall.h" #include "inferno.h" #include "segment.h" extern int wall_add_removable(); // Restores all the walls to original status extern int wall_restore_all(); // Reset a wall. extern void wall_reset(segment *seg, short side); // Adds a removable wall (medwall.c) extern int wall_add_removable(); // Adds a door (medwall.c) extern int wall_add_door(); // Adds an illusory wall (medwall.c) extern int wall_add_illusion(); // Removes a removable wall (medwall.c) extern int wall_remove_blastable(); // Adds a wall. (visually) extern int wall_add_to_curside(); extern int wall_add_to_markedside(sbyte type); // Removes a wall. (visually) extern int wall_remove(); // Removes a specific side. int wall_remove_side(segment *seg, short side); extern int bind_wall_to_control_center(); extern void close_wall_window(); extern void do_wall_window(); extern int wall_link_doors(); extern int wall_unlink_door(); extern void copy_group_walls(int old_group, int new_group); #endif dxx-rebirth-0.58.1-d1x/include/editor/objpage.h000066400000000000000000000021041217717257200212400ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * object selection stuff. * */ #ifndef _OBJPAGE_H #define _OBJPAGE_H #include "ui.h" struct d_event; int objpage_grab_current(int n); int objpage_goto_first(); void objpage_init( UI_DIALOG *dlg ); void objpage_close(); int objpage_do(struct d_event *event); extern void draw_object_picture(int id, vms_angvec *orient_angles, int type); #endif dxx-rebirth-0.58.1-d1x/include/editor/seguvs.h000066400000000000000000000017311217717257200211520ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for seguvs.c * */ #ifndef _SEGUVS_H #define _SEGUVS_H extern void assign_light_to_side(segment *sp, int sidenum); extern void assign_default_lighting_all(void); extern void stretch_uvs_from_curedge(segment *segp, int side); #endif dxx-rebirth-0.58.1-d1x/include/editor/texpage.h000066400000000000000000000021071217717257200212710ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Definitions for texpage.c * */ #ifndef _TEXPAGE_H #define _TEXPAGE_H #include "ui.h" struct d_event; extern int TextureLights; extern int TextureEffects; extern int TextureMetals; int texpage_grab_current(int n); int texpage_goto_first(); void texpage_init( UI_DIALOG * dlg ); void texpage_close(); int texpage_do(struct d_event *event); #endif dxx-rebirth-0.58.1-d1x/include/fix.h000066400000000000000000000000611217717257200171310ustar00rootroot00000000000000/* fix.h points to maths.h */ #include "maths.h" dxx-rebirth-0.58.1-d1x/include/func.h000066400000000000000000000033001217717257200172750ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/func.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:29 $ * * . * * $Log: func.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:29 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:02:09 donut * Import of d1x 1.37 source. * * Revision 1.1 1994/11/27 14:52:03 matt * Initial revision * * Revision 1.1 1994/11/21 14:13:31 matt * Initial revision * * Revision 1.1 1993/11/15 12:28:13 john * Initial revision * * */ #ifndef _FUNC_H #define _FUNC_H typedef struct { char * name; int nparams; int (*cfunction)(void); } FUNCTION; void func_init( FUNCTION * funtable, int size ); void func_close(); int (*func_get( char * name, int * numparams ))(void); int func_howmany(); int (*func_nget( int func_number, int * numparams, char **name ))(void); void func_set_param( int n, int value ); int func_get_param( int n ); int func_get_index( char * name ); #endif dxx-rebirth-0.58.1-d1x/include/gr.h000066400000000000000000000375621217717257200167730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Definitions for graphics lib. * */ #ifndef _GR_H #define _GR_H #include "pstypes.h" #include "fix.h" extern int HiresGFXAvailable; // some defines for transparency and blending #define TRANSPARENCY_COLOR 255 // palette entry of transparency color -- 255 on the PC #define GR_FADE_LEVELS 34 #define GR_FADE_OFF GR_FADE_LEVELS // yes, max means OFF - don't screw that up #define GR_BLEND_NORMAL 0 // normal blending #define GR_BLEND_ADDITIVE_A 1 // additive alpha blending #define GR_BLEND_ADDITIVE_C 2 // additive color blending #define GWIDTH grd_curcanv->cv_bitmap.bm_w #define GHEIGHT grd_curcanv->cv_bitmap.bm_h #define SWIDTH (grd_curscreen->sc_w) #define SHEIGHT (grd_curscreen->sc_h) #define HIRESMODE HiresGFXAvailable // descent.pig either contains hires or lowres graphics, not both #define MAX_BMP_SIZE(width, height) (4 + ((width) + 2) * (height)) #define SCRNS_DIR "screenshots/" typedef struct _grs_point { fix x,y; } grs_point; //these are control characters that have special meaning in the font code #define CC_COLOR 1 //next char is new foreground color #define CC_LSPACING 2 //next char specifies line spacing #define CC_UNDERLINE 3 //next char is underlined //now have string versions of these control characters (can concat inside a string) #define CC_COLOR_S "\x1" //next char is new foreground color #define CC_LSPACING_S "\x2" //next char specifies line spacing #define CC_UNDERLINE_S "\x3" //next char is underlined #define BM_LINEAR 0 #define BM_MODEX 1 #define BM_SVGA 2 #define BM_RGB15 3 //5 bits each r,g,b stored at 16 bits #define BM_SVGA15 4 #ifdef OGL #define BM_OGL 5 #endif /* def OGL */ #define SM(w,h) ((((u_int32_t)w)<<16)+(((u_int32_t)h)&0xFFFF)) #define SM_W(m) (m>>16) #define SM_H(m) (m&0xFFFF) #define SM_ORIGINAL 0 #define BM_FLAG_TRANSPARENT 1 #define BM_FLAG_SUPER_TRANSPARENT 2 #define BM_FLAG_NO_LIGHTING 4 #define BM_FLAG_RLE 8 // A run-length encoded bitmap. #define BM_FLAG_PAGED_OUT 16 // This bitmap's data is paged out. #define BM_FLAG_RLE_BIG 32 // for bitmaps that RLE to > 255 per row (i.e. cockpits) typedef struct _grs_bitmap { short bm_x,bm_y; // Offset from parent's origin short bm_w,bm_h; // width,height sbyte bm_type; // 0=Linear, 1=ModeX, 2=SVGA sbyte bm_flags; // bit 0 on means it has transparency. // bit 1 on means it has supertransparency // bit 2 on means it doesn't get passed through lighting. short bm_rowsize; // unsigned char offset to next row unsigned char * bm_data; // ptr to pixel data... // Linear = *parent+(rowsize*y+x) // ModeX = *parent+(rowsize*y+x/4) // SVGA = *parent+(rowsize*y+x) unsigned short bm_handle; //for application. initialized to 0 ubyte avg_color; // Average color of all pixels in texture map. fix avg_color_rgb[3]; // same as above but real rgb value to be used to textured objects that should emit light sbyte unused; // to 4-byte align. struct _grs_bitmap *bm_parent; #ifdef OGL struct _ogl_texture *gltexture; #endif /* def OGL */ } grs_bitmap; //font structure typedef struct _grs_font { short ft_w; // Width in pixels short ft_h; // Height in pixels short ft_flags; // Proportional? short ft_baseline; // ubyte ft_minchar; // First char defined by this font ubyte ft_maxchar; // Last char defined by this font short ft_bytewidth; // Width in unsigned chars ubyte * ft_data; // Ptr to raw data. ubyte ** ft_chars; // Ptrs to data for each char (required for prop font) short * ft_widths; // Array of widths (required for prop font) ubyte * ft_kerndata; // Array of kerning triplet data #ifdef OGL // These fields do not participate in disk i/o! grs_bitmap *ft_bitmaps; grs_bitmap ft_parent_bitmap; #endif /* def OGL */ } __pack__ grs_font; #define GRS_FONT_SIZE 28 // how much space it takes up on disk typedef struct _grs_canvas { grs_bitmap cv_bitmap; // the bitmap for this canvas short cv_color; // current color int cv_fade_level; // transparency level ubyte cv_blend_func; // blending function to use short cv_drawmode; // fill,XOR,etc. grs_font * cv_font; // the currently selected font short cv_font_fg_color; // current font foreground color (-1==Invisible) short cv_font_bg_color; // current font background color (-1==Invisible) } grs_canvas; typedef struct _grs_screen { // This is a video screen grs_canvas sc_canvas; // Represents the entire screen int sc_mode; // Video mode number short sc_w, sc_h; // Actual Width and Height fix sc_aspect; //aspect ratio (w/h) for this screen } grs_screen; //========================================================================= // System functions: // setup and set mode. this creates a grs_screen structure and sets // grd_curscreen to point to it. grs_curcanv points to this screen's // canvas. Saves the current VGA state and screen mode. int gr_init(int mode); int gr_list_modes( u_int32_t gsmodes[] ); int gr_check_mode(u_int32_t mode); int gr_set_mode(u_int32_t mode); void gr_set_attributes(void); extern void gr_pal_setblock( int start, int number, unsigned char * pal ); extern void gr_pal_getblock( int start, int number, unsigned char * pal ); //shut down the 2d. Restore the screen mode. void gr_close(void); //========================================================================= // Canvas functions: // Makes a new canvas. allocates memory for the canvas and its bitmap, // including the raw pixel buffer. grs_canvas *gr_create_canvas(int w, int h); // Creates a canvas that is part of another canvas. this can be used to make // a window on the screen. the canvas structure is malloc'd; the address of // the raw pixel data is inherited from the parent canvas. grs_canvas *gr_create_sub_canvas(grs_canvas *canv,int x,int y,int w, int h); // Initialize the specified canvas. the raw pixel data buffer is passed as // a parameter. no memory allocation is performed. void gr_init_canvas(grs_canvas *canv,unsigned char *pixdata,int pixtype, int w,int h); // Initialize the specified sub canvas. no memory allocation is performed. void gr_init_sub_canvas(grs_canvas *,grs_canvas *src,int x,int y,int w, int h); // Free up the canvas and its pixel data. void gr_free_canvas(grs_canvas *canv); // Free up the canvas. do not free the pixel data, which belongs to the // parent canvas. void gr_free_sub_canvas(grs_canvas *canv); // Clear the current canvas to the specified color void gr_clear_canvas(int color); //========================================================================= // Bitmap functions: // these are the two workhorses, the others just use these extern void gr_init_bitmap( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline, unsigned char * data ); extern void gr_init_sub_bitmap (grs_bitmap *bm, grs_bitmap *bmParent, int x, int y, int w, int h ); extern void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline); // Allocate a bitmap and its pixel data buffer. grs_bitmap *gr_create_bitmap(int w,int h); // Allocated a bitmap and makes its data be raw_data that is already somewhere. grs_bitmap *gr_create_bitmap_raw(int w, int h, unsigned char * raw_data ); // Creates a bitmap which is part of another bitmap grs_bitmap *gr_create_sub_bitmap(grs_bitmap *bm,int x,int y,int w, int h); // Free the bitmap and its pixel data void gr_free_bitmap(grs_bitmap *bm); // Free the bitmap's data void gr_free_bitmap_data (grs_bitmap *bm); void gr_init_bitmap_data (grs_bitmap *bm); // Free the bitmap, but not the pixel data buffer void gr_free_sub_bitmap(grs_bitmap *bm); void gr_bm_pixel( grs_bitmap * bm, int x, int y, unsigned char color ); void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_bm_ubitblt( int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_bm_ubitbltm(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void gr_update_buffer( void * sbuf1, void * sbuf2, void * dbuf, int size ); void gr_set_bitmap_flags(grs_bitmap *pbm, int flags); void gr_set_transparent(grs_bitmap *pbm, int bTransparent); void gr_set_super_transparent(grs_bitmap *pbm, int bTransparent); void gr_set_bitmap_data(grs_bitmap *bm, unsigned char *data); //========================================================================= // Color functions: // When this function is called, the guns are set to gr_palette, and // the palette stays the same until gr_close is called void gr_use_palette_table(char * filename ); //========================================================================= // Drawing functions: // For solid, XOR, or other fill modes. int gr_set_drawmode(int mode); // Sets the color in the current canvas. void gr_setcolor(int color); // Sets transparency and blending function void gr_settransblend(int fade_level, ubyte blend_func); // Draw a polygon into the current canvas in the current color and drawmode. // verts points to an ordered list of x,y pairs. the polygon should be // convex; a concave polygon will be handled in some reasonable manner, // but not necessarily shaded as a concave polygon. It shouldn't hang. // probably good solution is to shade from minx to maxx on each scan line. // int should really be fix void gr_poly(int nverts,int *verts); void gr_upoly(int nverts,int *verts); // Draws a point into the current canvas in the current color and drawmode. void gr_pixel(int x,int y); void gr_upixel(int x,int y); // Gets a pixel; unsigned char gr_gpixel( grs_bitmap * bitmap, int x, int y ); unsigned char gr_ugpixel( grs_bitmap * bitmap, int x, int y ); // Draws a line into the current canvas in the current color and drawmode. int gr_line(fix x0,fix y0,fix x1,fix y1); int gr_uline(fix x0,fix y0,fix x1,fix y1); // Draws an anti-aliased line into the current canvas in the current color and drawmode. int gr_aaline(fix x0,fix y0,fix x1,fix y1); int gr_uaaline(fix x0,fix y0,fix x1,fix y1); // Draw the bitmap into the current canvas at the specified location. void gr_bitmap(int x,int y,grs_bitmap *bm); void gr_ubitmap(int x,int y,grs_bitmap *bm); void gr_bitmap_scale_to(grs_bitmap *src, grs_bitmap *dst); void show_fullscr(grs_bitmap *bm); // Find transparent area in bitmap void gr_bitblt_find_transparent_area(grs_bitmap *bm, int *minx, int *miny, int *maxx, int *maxy); // bitmap function with transparency void gr_bitmapm( int x, int y, grs_bitmap *bm ); void gr_ubitmapm( int x, int y, grs_bitmap *bm ); // Draw a rectangle into the current canvas. void gr_rect(int left,int top,int right,int bot); void gr_urect(int left,int top,int right,int bot); // Draw a filled circle int gr_disk(fix x,fix y,fix r); // Draw an outline circle int gr_circle(fix x,fix y,fix r); int gr_ucircle(fix x,fix y,fix r); // Draw an unfilled rectangle into the current canvas void gr_box(int left,int top,int right,int bot); void gr_ubox(int left,int top,int right,int bot); void gr_scanline( int x1, int x2, int y ); void gr_uscanline( int x1, int x2, int y ); // Reads in a font file... current font set to this one. grs_font * gr_init_font( const char * fontfile ); void gr_close_font( grs_font * font ); // Writes a string using current font. Returns the next column after last char. void gr_set_curfont( grs_font * ); void gr_set_fontcolor( int fg_color, int bg_color ); int gr_string(int x, int y, const char *s ); int gr_ustring(int x, int y, const char *s ); int gr_printf( int x, int y, const char * format, ... ); int gr_uprintf( int x, int y, const char * format, ... ); void gr_get_string_size(const char *s, int *string_width, int *string_height, int *average_width ); // From roller.c void rotate_bitmap(grs_bitmap *bp, grs_point *vertbuf, int light_value); // From scale.c void scale_bitmap(grs_bitmap *bp, grs_point *vertbuf, int orientation ); //=========================================================================== // Global variables extern grs_canvas *grd_curcanv; //active canvas extern grs_screen *grd_curscreen; //active screen extern unsigned char Test_bitmap_data[64*64]; extern unsigned int FixDivide( unsigned int x, unsigned int y ); extern void gr_set_current_canvas( grs_canvas *canv ); //flags for fonts #define FT_COLOR 1 #define FT_PROPORTIONAL 2 #define FT_KERNED 4 // Special effects extern void gr_snow_out(int num_dots); extern void test_rotate_bitmap(void); extern void rotate_bitmap(grs_bitmap *bp, grs_point *vertbuf, int light_value); extern ubyte gr_palette[256*3]; extern ubyte gr_fade_table[256*GR_FADE_LEVELS]; extern ubyte gr_inverse_table[32*32*32]; extern ushort gr_palette_selector; extern ushort gr_inverse_table_selector; extern ushort gr_fade_table_selector; // Remaps a bitmap into the current palette. If transparent_color is // between 0 and 255 then all occurances of that color are mapped to // whatever color the 2d uses for transparency. This is normally used // right after a call to iff_read_bitmap like this: // iff_error = iff_read_bitmap(filename,new,BM_LINEAR,newpal); // if (iff_error != IFF_NO_ERROR) Error("Can't load IFF file <%s>, error=%d",filename,iff_error); // if ( iff_has_transparency ) // gr_remap_bitmap( new, newpal, iff_transparent_color ); // else // gr_remap_bitmap( new, newpal, -1 ); extern void gr_remap_bitmap( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color ); // Same as above, but searches using gr_find_closest_color which uses // 18-bit accurracy instead of 15bit when translating colors. extern void gr_remap_bitmap_good( grs_bitmap * bmp, ubyte * palette, int transparent_color, int super_transparent_color ); extern void build_colormap_good( ubyte * palette, ubyte * colormap, int * freq ); extern void gr_palette_step_up( int r, int g, int b ); extern void gr_bitmap_check_transparency( grs_bitmap * bmp ); #define BM_RGB(r,g,b) ( (((r)&31)<<10) | (((g)&31)<<5) | ((b)&31) ) #define BM_XRGB(r,g,b) gr_find_closest_color( (r)*2,(g)*2,(b)*2 ) // Given: r,g,b, each in range of 0-63, return the color index that // best matches the input. int gr_find_closest_color( int r, int g, int b ); int gr_find_closest_color_15bpp( int rgb ); extern void gr_merge_textures( ubyte * lower, ubyte * upper, ubyte * dest ); extern void gr_merge_textures_1( ubyte * lower, ubyte * upper, ubyte * dest ); extern void gr_merge_textures_2( ubyte * lower, ubyte * upper, ubyte * dest ); extern void gr_merge_textures_3( ubyte * lower, ubyte * upper, ubyte * dest ); extern void gr_flip(void); extern void gr_set_draw_buffer(int buf); /* * must return 0 if windowed, 1 if fullscreen */ int gr_check_fullscreen(void); /* * returns state after toggling (ie, same as if you had called * check_fullscreen immediatly after) */ int gr_toggle_fullscreen(void); void ogl_do_palfx(void); void ogl_init_pixel_buffers(int w, int h); void ogl_close_pixel_buffers(void); #endif /* def _GR_H */ dxx-rebirth-0.58.1-d1x/include/grdef.h000066400000000000000000000074601217717257200174440ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/grdef.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:35 $ * * Internal definitions for graphics lib. * * $Log: grdef.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:35 zicodxx * initial import * * Revision 1.2 1999/11/20 10:05:16 donut * variable size menu patch from Jan Bobrowski. Variable menu font size support and a bunch of fixes for menus that didn't work quite right, by me (MPM). * * Revision 1.1.1.1 1999/06/14 22:02:14 donut * Import of d1x 1.37 source. * * Revision 1.5 1995/09/14 15:36:33 allender * added stuff for 68k version * * Revision 1.4 1995/07/05 16:10:57 allender * gr_linear_movsd prototype changes * * Revision 1.3 1995/04/19 14:39:28 allender * changed function prototype * * Revision 1.2 1995/04/18 09:49:53 allender * *** empty log message *** * * Revision 1.1 1995/03/09 09:04:56 allender * Initial revision * * * --- PC RCS information --- * Revision 1.8 1994/05/06 12:50:09 john * Added supertransparency; neatend things up; took out warnings. * * Revision 1.7 1994/01/25 11:40:29 john * Added gr_check_mode function. * * Revision 1.6 1993/10/15 16:22:53 john * y * * Revision 1.5 1993/09/29 17:31:00 john * added gr_vesa_pixel * * Revision 1.4 1993/09/29 16:14:43 john * added global canvas descriptors. * * Revision 1.3 1993/09/08 17:38:02 john * Looking for errors * * Revision 1.2 1993/09/08 15:54:29 john * *** empty log message *** * * Revision 1.1 1993/09/08 11:37:57 john * Initial revision * * */ #define USE_2D_ASM 1 extern void gr_set_buffer(int w, int h, int r, int (*buffer_func)()); extern void gr_pal_setblock( int start, int n, unsigned char * palette ); extern void gr_pal_getblock( int start, int n, unsigned char * palette ); extern void gr_pal_setone( int index, unsigned char red, unsigned char green, unsigned char blue ); void gr_linear_movsb( ubyte * source, ubyte * dest, int nbytes); void gr_linear_movsw( ubyte * source, ubyte * dest, int nbytes); #if ( defined(__MWERKS__) && defined(__MC68K__) && defined(USE_2D_ASM) ) void gr_linear_movsd(ubyte * src:__A0, ubyte * dest:__A1, uint num_pixels:__D0 ); #else void gr_linear_movsd( ubyte * source, ubyte * dest, unsigned int nbytes); #endif void gr_linear_rep_movsd_2x( ubyte * source, ubyte * dest, uint nbytes); void gr_linear_stosd( ubyte * dest, unsigned char color, unsigned int nbytes); extern unsigned int gr_var_color; extern unsigned int gr_var_bwidth; extern unsigned char * gr_var_bitmap; void gr_linear_line( int x0, int y0, int x1, int y1); extern unsigned int Table8to32[256]; #ifdef __MSDOS__ extern unsigned char * gr_video_memory; #endif #define MINX 0 #define MINY 0 #define MAXX (GWIDTH-1) #define MAXY (GHEIGHT-1) #define TYPE grd_curcanv->cv_bitmap.bm_type #define DATA grd_curcanv->cv_bitmap.bm_data #define XOFFSET grd_curcanv->cv_bitmap.bm_x #define YOFFSET grd_curcanv->cv_bitmap.bm_y #define ROWSIZE grd_curcanv->cv_bitmap.bm_rowsize #define COLOR grd_curcanv->cv_color void order( int *x1, int *x2 ); dxx-rebirth-0.58.1-d1x/include/hmp.h000066400000000000000000000036761217717257200171460ustar00rootroot00000000000000#ifndef __HMP_H #define __HMP_H #ifdef _WIN32 #include #include #endif #include "physfsx.h" #define HMP_TRACKS 32 #ifdef _WIN32 #define MIDI_VOLUME_SCALE 128 #define HMP_BUFFERS 4 #define HMP_BUFSIZE 1024 #define HMP_INVALID_FILE -1 #define HMP_OUT_OF_MEM -2 #define HMP_MM_ERR -3 #define HMP_EOF 1 #define MIDI_CONTROL_CHANGE 0xB #define MIDI_PROGRAM_CHANGE 0xC #define MIDI_BANK_SELECT_MSB 0x00 #define MIDI_BANK_SELECT_LSB 0x20 #define MIDI_VOLUME 0x07 #define MIDI_PANPOT 0x0A #define MIDI_REVERB 0x5B #define MIDI_CHORUS 0x5D #define MIDI_ALL_SOUNDS_OFF 0x78 #define MIDI_RESET_ALL_CONTROLLERS 0x79 #define MIDI_ALL_NOTES_OFF 0x7B #define HMP_LOOP_START 0x6E #define HMP_LOOP_END 0x6F #endif #ifdef _WIN32 typedef struct event { unsigned int delta; unsigned char msg[3]; unsigned char *data; unsigned int datalen; } event; #endif typedef struct hmp_track { unsigned char *data; unsigned char *loop; unsigned int len; unsigned char *cur; unsigned int left; unsigned int cur_time; unsigned int loop_start; int loop_set; } hmp_track; typedef struct hmp_file { PHYSFS_sint64 filesize; int num_trks; hmp_track trks[HMP_TRACKS]; unsigned int cur_time; unsigned int loop_start; unsigned int loop_end; int looping; int tempo; #ifdef _WIN32 MIDIHDR *evbuf; HMIDISTRM hmidi; UINT devid; #endif unsigned char *pending; unsigned int pending_size; unsigned int pending_event; int stop; int bufs_in_mm; int bLoop; unsigned int midi_division; } hmp_file; hmp_file *hmp_open(const char *filename); void hmp_close(hmp_file *hmp); void hmp2mid(char *hmp_name, unsigned char **midbuf, unsigned int *midlen); #ifdef _WIN32 void hmp_setvolume(hmp_file *hmp, int volume); int hmp_play(hmp_file *hmp, int bLoop); void hmp_pause(hmp_file *hmp); void hmp_resume(hmp_file *hmp); void hmp_reset(); #endif #endif dxx-rebirth-0.58.1-d1x/include/iff.h000066400000000000000000000112421217717257200171120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/iff.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:20 $ * * Header for IFF routines * * $Log: iff.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:20 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:02:15 donut * Import of d1x 1.37 source. * * Revision 1.12 1994/11/07 21:26:53 matt * Added new function iff_read_into_bitmap() * * Revision 1.11 1994/05/06 19:37:38 matt * Improved error handling and checking * * Revision 1.10 1994/04/16 20:12:54 matt * Made masked (stenciled) bitmaps work * * Revision 1.9 1994/04/13 23:46:00 matt * Added function, iff_errormsg(), which returns ptr to error message. * * Revision 1.8 1994/04/13 23:27:10 matt * Put in support for anim brushes (.abm files) * * Revision 1.7 1994/04/06 23:08:02 matt * Cleaned up code; added prototype (but no new code) for anim brush read * * Revision 1.6 1994/01/22 14:40:59 john * Fixed bug with declareations. * * Revision 1.5 1994/01/22 14:23:13 john * Added global vars to check transparency * * Revision 1.4 1993/10/27 12:47:42 john * Extended the comments * * Revision 1.3 1993/09/22 19:17:20 matt * Fixed handling of pad byte in ILBM/PPB body - was writing pad byte to * destination buffer. * * Revision 1.2 1993/09/08 19:23:25 matt * Added additional return code, IFF_BAD_BM_TYPE * * Revision 1.1 1993/09/08 14:24:21 matt * Initial revision * * */ #ifndef _IFF_H #define _IFF_H #include "pstypes.h" #include "gr.h" //Prototypes for IFF library functions int iff_read_bitmap(char *ifilename,grs_bitmap *bm,int bitmap_type,ubyte *palette); //reads an IFF file into a grs_bitmap structure. fills in palette if not null //returns error codes - see IFF.H. see GR.H for bitmap_type //MEM DETAILS: This routines assumes that you already have the grs_bitmap //structure allocated, but that you don't have the data for this bitmap //allocated. In other words, do this: // grs_bitmap * MyPicture; // MALLOC( MyPicture, grs_bitmap, 1); // iff_read_bitmap( filename, MyPicture, BM_LINEAR, NULL ); // ...do whatever with your bitmap ... // gr_free_bitmap( MyPicture ); // exit(0) //like iff_read_bitmap(), but reads into a bitmap that already exists, //without allocating memory for the bitmap. int iff_read_into_bitmap(char *ifilename,grs_bitmap *bm, sbyte *palette); //read in animator brush (.abm) file //fills in array of pointers, and n_bitmaps. //returns iff error codes. max_bitmaps is size of array. int iff_read_animbrush(char *ifilename,grs_bitmap **bm,int max_bitmaps,int *n_bitmaps,ubyte *palette); // After a read extern ubyte iff_transparent_color; extern ubyte iff_has_transparency; // 0=no transparency, 1=iff_transparent_color is valid int iff_write_bitmap(char *ofilename,grs_bitmap *bm,ubyte *palette); //writes an IFF file from a grs_bitmap structure. writes palette if not null //returns error codes - see IFF.H. //function to return pointer to error message const char *iff_errormsg(int error_number); //Error codes for read & write routines #define IFF_NO_ERROR 0 //everything is fine, have a nice day #define IFF_NO_MEM 1 //not enough mem for loading or processing #define IFF_UNKNOWN_FORM 2 //IFF file, but not a bitmap #define IFF_NOT_IFF 3 //this isn't even an IFF file #define IFF_NO_FILE 4 //cannot find or open file #define IFF_BAD_BM_TYPE 5 //tried to save invalid type, like BM_RGB15 #define IFF_CORRUPT 6 //bad data in file #define IFF_FORM_ANIM 7 //this is an anim, with non-anim load rtn #define IFF_FORM_BITMAP 8 //this is not an anim, with anim load rtn #define IFF_TOO_MANY_BMS 9 //anim read had more bitmaps than room for #define IFF_UNKNOWN_MASK 10 //unknown masking type #define IFF_READ_ERROR 11 //error reading from file #define IFF_BM_MISMATCH 12 //bm being loaded doesn't match bm loaded into #endif dxx-rebirth-0.58.1-d1x/include/ignorecase.h000066400000000000000000000065001217717257200204660ustar00rootroot00000000000000/** \file ignorecase.h */ /** * \mainpage PhysicsFS ignorecase * * This is an extension to PhysicsFS to let you handle files in a * case-insensitive manner, regardless of what sort of filesystem or * archive they reside in. It does this by enumerating directories as * needed and manually locating matching entries. * * Please note that this brings with it some caveats: * - On filesystems that are case-insensitive to start with, such as those * used on Windows or MacOS, you are adding extra overhead. * - On filesystems that are case-sensitive, you might select the wrong dir * or file (which brings security considerations and potential bugs). This * code favours exact case matches, but you will lose access to otherwise * duplicate filenames, or you might go down a wrong directory tree, etc. * In practive, this is rarely a problem, but you need to be aware of it. * - This doesn't do _anything_ with the write directory; you're on your * own for opening the right files for writing. You can sort of get around * this by adding your write directory to the search path, but then the * interpolated directory tree can screw you up even more. * * This code should be considered an aid for legacy code. New development * shouldn't do dumbass things that require this aid in the first place. :) * * Usage: Set up PhysicsFS as you normally would, then use * PHYSFSEXT_locateCorrectCase() to get a "correct" pathname to pass to * functions like PHYSFS_openRead(), etc. * * License: this code is public domain. I make no warranty that it is useful, * correct, harmless, or environmentally safe. * * This particular file may be used however you like, including copying it * verbatim into a closed-source project, exploiting it commercially, and * removing any trace of my name from the source (although I hope you won't * do that). I welcome enhancements and corrections to this file, but I do * not require you to send me patches if you make changes. This code has * NO WARRANTY. * * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. * Please see LICENSE in the root of the source tree. * * \author Ryan C. Gordon. */ /** * \fn int PHYSFSEXT_locateCorrectCase(char *buf) * \brief Find an existing filename with matching case. * * This function will look for a path/filename that matches the passed in * buffer. Each element of the buffer's path is checked for a * case-insensitive match. The buffer must specify a null-terminated string * in platform-independent notation. * * Please note results may be skewed differently depending on whether symlinks * are enabled or not. * * Each element of the buffer is overwritten with the actual case of an * existing match. If there is no match, the search aborts and reports an * error. Exact matches are favored over case-insensitive matches. * * THIS IS RISKY. Please do not use this function for anything but crappy * legacy code. * * \param buf Buffer with null-terminated string of path/file to locate. * This buffer will be modified by this function. * \return zero if match was found, -1 if the final element (the file itself) * is missing, -2 if one of the parent directories is missing. */ int PHYSFSEXT_locateCorrectCase(char *buf); /* end of ignorecase.h ... */ dxx-rebirth-0.58.1-d1x/include/internal.h000066400000000000000000000050571217717257200201710ustar00rootroot00000000000000/* prototypes for function calls between files within the OpenGL module */ #ifndef _INTERNAL_H_ #define _INTERNAL_H_ #include "ogl_init.h" // interface to OpenGL module /* I assume this ought to be >= MAX_BITMAP_FILES in piggy.h? */ #define OGL_TEXTURE_LIST_SIZE 20000 extern ogl_texture ogl_texture_list[OGL_TEXTURE_LIST_SIZE]; void ogl_init_texture_list_internal(void); void ogl_smash_texture_list_internal(void); void ogl_vivify_texture_list_internal(void); extern int ogl_brightness_ok; extern int ogl_brightness_r, ogl_brightness_g, ogl_brightness_b; extern int ogl_fullscreen; extern int GL_TEXTURE_2D_enabled; #define OGL_ENABLE2(a,f) {if (a ## _enabled!=1) {f;a ## _enabled=1;}} #define OGL_DISABLE2(a,f) {if (a ## _enabled!=0) {f;a ## _enabled=0;}} //#define OGL_ENABLE(a) OGL_ENABLE2(a,glEnable(a)) //#define OGL_DISABLE(a) OGL_DISABLE2(a,glDisable(a)) #define OGL_ENABLE(a) OGL_ENABLE2(GL_ ## a,glEnable(GL_ ## a)) #define OGL_DISABLE(a) OGL_DISABLE2(GL_ ## a,glDisable(GL_ ## a)) //#define OGL_TEXCLAMP() OGL_ENABLE2(GL_texclamp,glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);) //#define OGL_TEXREPEAT() OGL_DISABLE2(GL_texclamp,glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);) //#define OGL_SETSTATE(a,s,f) {if (a ## _state!=s) {f;a ## _state=s;}} //#define OGL_TEXENV(p,m) OGL_SETSTATE(p,m,glTexEnvi(GL_TEXTURE_ENV, p,m)); //#define OGL_TEXPARAM(p,m) OGL_SETSTATE(p,m,glTexParameteri(GL_TEXTURE_2D,p,m)) extern int last_width,last_height; #define OGL_VIEWPORT(x,y,w,h){if (w!=last_width || h!=last_height){glViewport(x,grd_curscreen->sc_canvas.cv_bitmap.bm_h-y-h,w,h);last_width=w;last_height=h;}} //platform specific funcs extern void ogl_swap_buffers_internal(void); extern unsigned char *ogl_pal; //whee //#define PAL2Tr(c) ((gr_palette[c*3]+gr_palette_gamma)/63.0) //#define PAL2Tg(c) ((gr_palette[c*3+1]+gr_palette_gamma)/63.0) //#define PAL2Tb(c) ((gr_palette[c*3+2]+gr_palette_gamma)/63.0) //#define PAL2Tr(c) ((gr_palette[c*3])/63.0) //#define PAL2Tg(c) ((gr_palette[c*3+1])/63.0) //#define PAL2Tb(c) ((gr_palette[c*3+2])/63.0) #define CPAL2Tr(c) ((gr_current_pal[c*3])/63.0) #define CPAL2Tg(c) ((gr_current_pal[c*3+1])/63.0) #define CPAL2Tb(c) ((gr_current_pal[c*3+2])/63.0) #define PAL2Tr(c) ((ogl_pal[c*3])/63.0) #define PAL2Tg(c) ((ogl_pal[c*3+1])/63.0) #define PAL2Tb(c) ((ogl_pal[c*3+2])/63.0) //inline GLfloat PAL2Tr(int c); //inline GLfloat PAL2Tg(int c); //inline GLfloat PAL2Tb(int c); #endif // _INTERNAL_H_ dxx-rebirth-0.58.1-d1x/include/loadgl.h000066400000000000000000002730231217717257200176170ustar00rootroot00000000000000//loadgl.h - dynamic opengl loading - curtousy (sp) of Jeff Slutter #ifndef __LOADGL_H__ #define __LOADGL_H__ #if defined(_WIN32) #include #define OGLFUNCCALL __stdcall #else #define OGLFUNCCALL #endif #include #include "pstypes.h" //gl extensions. #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #endif #ifndef GL_SGIS_multitexture #define GL_SGIS_multitexture 1 #define GL_TEXTURE0_SGIS 0x835F #define GL_TEXTURE1_SGIS 0x8360 #endif #ifndef GL_TEXTURE_INDEX_SIZE_EXT #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED #endif #ifndef GL_SCISSOR_TEST #define GL_SCISSOR_TEST 0x0C11 #endif #ifndef GL_CLAMP_TO_EDGE #define GL_CLAMP_TO_EDGE 0x812F #endif #ifdef _cplusplus #define OEXTERN extern "C" #else #define OEXTERN extern #define true 1 #define false 0 #endif #ifdef DECLARE_VARS #define DEFVAR #else #define DEFVAR OEXTERN #endif #define glAccum dglAccum #define glAlphaFunc dglAlphaFunc #define glAreTexturesResident dglAreTexturesResident #define glArrayElement dglArrayElement #define glBegin dglBegin #define glBindTexture dglBindTexture #define glBitmap dglBitmap #define glBlendFunc dglBlendFunc #define glCallList dglCallList #define glCallLists dglCallLists #define glClear dglClear #define glClearAccum dglClearAccum #define glClearColor dglClearColor #define glClearDepth dglClearDepth #define glClearIndex dglClearIndex #define glClearStencil dglClearStencil #define glClipPlane dglClipPlane #define glColor3b dglColor3b #define glColor3bv dglColor3bv #define glColor3d dglColor3d #define glColor3dv dglColor3dv #define glColor3f dglColor3f #define glColor3fv dglColor3fv #define glColor3i dglColor3i #define glColor3iv dglColor3iv #define glColor3s dglColor3s #define glColor3sv dglColor3sv #define glColor3ub dglColor3ub #define glColor3ubv dglColor3ubv #define glColor3ui dglColor3ui #define glColor3uiv dglColor3uiv #define glColor3us dglColor3us #define glColor3usv dglColor3usv #define glColor4b dglColor4b #define glColor4bv dglColor4bv #define glColor4d dglColor4d #define glColor4dv dglColor4dv #define glColor4f dglColor4f #define glColor4fv dglColor4fv #define glColor4i dglColor4i #define glColor4iv dglColor4iv #define glColor4s dglColor4s #define glColor4sv dglColor4sv #define glColor4ub dglColor4ub #define glColor4ubv dglColor4ubv #define glColor4ui dglColor4ui #define glColor4uiv dglColor4uiv #define glColor4us dglColor4us #define glColor4usv dglColor4usv #define glColorMask dglColorMask #define glColorMaterial dglColorMaterial #define glColorPointer dglColorPointer #define glCopyPixels dglCopyPixels #define glCopyTexImage1D dglCopyTexImage1D #define glCopyTexImage2D dglCopyTexImage2D #define glCopyTexSubImage1D dglCopyTexSubImage1D #define glCopyTexSubImage2D dglCopyTexSubImage2D #define glCullFace dglCullFace #define glDeleteLists dglDeleteLists #define glDeleteTextures dglDeleteTextures #define glDepthFunc dglDepthFunc #define glDepthMask dglDepthMask #define glDepthRange dglDepthRange #define glDisable dglDisable #define glDisableClientState dglDisableClientState #define glDrawArrays dglDrawArrays #define glDrawBuffer dglDrawBuffer #define glDrawElements dglDrawElements #define glDrawPixels dglDrawPixels #define glEdgeFlag dglEdgeFlag #define glEdgeFlagPointer dglEdgeFlagPointer #define glEdgeFlagv dglEdgeFlagv #define glEnable dglEnable #define glEnableClientState dglEnableClientState #define glEnd dglEnd #define glEndList dglEndList #define glEvalCoord1d dglEvalCoord1d #define glEvalCoord1dv dglEvalCoord1dv #define glEvalCoord1f dglEvalCoord1f #define glEvalCoord1fv dglEvalCoord1fv #define glEvalCoord2d dglEvalCoord2d #define glEvalCoord2dv dglEvalCoord2dv #define glEvalCoord2f dglEvalCoord2f #define glEvalCoord2fv dglEvalCoord2fv #define glEvalMesh1 dglEvalMesh1 #define glEvalMesh2 dglEvalMesh2 #define glEvalPoint1 dglEvalPoint1 #define glEvalPoint2 dglEvalPoint2 #define glFeedbackBuffer dglFeedbackBuffer #define glFinish dglFinish #define glFlush dglFlush #define glFogf dglFogf #define glFogfv dglFogfv #define glFogi dglFogi #define glFogiv dglFogiv #define glFrontFace dglFrontFace #define glFrustum dglFrustum #define glGenLists dglGenLists #define glGenTextures dglGenTextures #define glGetBooleanv dglGetBooleanv #define glGetClipPlane dglGetClipPlane #define glGetDoublev dglGetDoublev #define glGetError dglGetError #define glGetFloatv dglGetFloatv #define glGetIntegerv dglGetIntegerv #define glGetLightfv dglGetLightfv #define glGetLightiv dglGetLightiv #define glGetMapdv dglGetMapdv #define glGetMapfv dglGetMapfv #define glGetMapiv dglGetMapiv #define glGetMaterialfv dglGetMaterialfv #define glGetMaterialiv dglGetMaterialiv #define glGetPixelMapfv dglGetPixelMapfv #define glGetPixelMapuiv dglGetPixelMapuiv #define glGetPixelMapusv dglGetPixelMapusv #define glGetPointerv dglGetPointerv #define glGetPolygonStipple dglGetPolygonStipple #define glGetString dglGetString #define glGetTexEnvfv dglGetTexEnvfv #define glGetTexEnviv dglGetTexEnviv #define glGetTexGendv dglGetTexGendv #define glGetTexGenfv dglGetTexGenfv #define glGetTexGeniv dglGetTexGeniv #define glGetTexImage dglGetTexImage #define glGetTexLevelParameterfv dglGetTexLevelParameterfv #define glGetTexLevelParameteriv dglGetTexLevelParameteriv #define glGetTexParameterfv dglGetTexParameterfv #define glGetTexParameteriv dglGetTexParameteriv #define glHint dglHint #define glIndexMask dglIndexMask #define glIndexPointer dglIndexPointer #define glIndexd dglIndexd #define glIndexdv dglIndexdv #define glIndexf dglIndexf #define glIndexfv dglIndexfv #define glIndexi dglIndexi #define glIndexiv dglIndexiv #define glIndexs dglIndexs #define glIndexsv dglIndexsv #define glIndexub dglIndexub #define glIndexubv dglIndexubv #define glInitNames dglInitNames #define glInterleavedArrays dglInterleavedArrays #define glIsEnabled dglIsEnabled #define glIsList dglIsList #define glIsTexture dglIsTexture #define glLightModelf dglLightModelf #define glLightModelfv dglLightModelfv #define glLightModeli dglLightModeli #define glLightModeliv dglLightModeliv #define glLightf dglLightf #define glLightfv dglLightfv #define glLighti dglLighti #define glLightiv dglLightiv #define glLineStipple dglLineStipple #define glLineWidth dglLineWidth #define glListBase dglListBase #define glLoadIdentity dglLoadIdentity #define glLoadMatrixd dglLoadMatrixd #define glLoadMatrixf dglLoadMatrixf #define glLoadName dglLoadName #define glLogicOp dglLogicOp #define glMap1d dglMap1d #define glMap1f dglMap1f #define glMap2d dglMap2d #define glMap2f dglMap2f #define glMapGrid1d dglMapGrid1d #define glMapGrid1f dglMapGrid1f #define glMapGrid2d dglMapGrid2d #define glMapGrid2f dglMapGrid2f #define glMaterialf dglMaterialf #define glMaterialfv dglMaterialfv #define glMateriali dglMateriali #define glMaterialiv dglMaterialiv #define glMatrixMode dglMatrixMode #define glMultMatrixd dglMultMatrixd #define glMultMatrixf dglMultMatrixf #define glNewList dglNewList #define glNormal3b dglNormal3b #define glNormal3bv dglNormal3bv #define glNormal3d dglNormal3d #define glNormal3dv dglNormal3dv #define glNormal3f dglNormal3f #define glNormal3fv dglNormal3fv #define glNormal3i dglNormal3i #define glNormal3iv dglNormal3iv #define glNormal3s dglNormal3s #define glNormal3sv dglNormal3sv #define glNormalPointer dglNormalPointer #define glOrtho dglOrtho #define glPassThrough dglPassThrough #define glPixelMapfv dglPixelMapfv #define glPixelMapuiv dglPixelMapuiv #define glPixelMapusv dglPixelMapusv #define glPixelStoref dglPixelStoref #define glPixelStorei dglPixelStorei #define glPixelTransferf dglPixelTransferf #define glPixelTransferi dglPixelTransferi #define glPixelZoom dglPixelZoom #define glPointSize dglPointSize #define glPolygonMode dglPolygonMode #define glPolygonOffset dglPolygonOffset #define glPolygonStipple dglPolygonStipple #define glPopAttrib dglPopAttrib #define glPopClientAttrib dglPopClientAttrib #define glPopMatrix dglPopMatrix #define glPopName dglPopName #define glPrioritizeTextures dglPrioritizeTextures #define glPushAttrib dglPushAttrib #define glPushClientAttrib dglPushClientAttrib #define glPushMatrix dglPushMatrix #define glPushName dglPushName #define glRasterPos2d dglRasterPos2d #define glRasterPos2dv dglRasterPos2dv #define glRasterPos2f dglRasterPos2f #define glRasterPos2fv dglRasterPos2fv #define glRasterPos2i dglRasterPos2i #define glRasterPos2iv dglRasterPos2iv #define glRasterPos2s dglRasterPos2s #define glRasterPos2sv dglRasterPos2sv #define glRasterPos3d dglRasterPos3d #define glRasterPos3dv dglRasterPos3dv #define glRasterPos3f dglRasterPos3f #define glRasterPos3fv dglRasterPos3fv #define glRasterPos3i dglRasterPos3i #define glRasterPos3iv dglRasterPos3iv #define glRasterPos3s dglRasterPos3s #define glRasterPos3sv dglRasterPos3sv #define glRasterPos4d dglRasterPos4d #define glRasterPos4dv dglRasterPos4dv #define glRasterPos4f dglRasterPos4f #define glRasterPos4fv dglRasterPos4fv #define glRasterPos4i dglRasterPos4i #define glRasterPos4iv dglRasterPos4iv #define glRasterPos4s dglRasterPos4s #define glRasterPos4sv dglRasterPos4sv #define glReadBuffer dglReadBuffer #define glReadPixels dglReadPixels #define glRectd dglRectd #define glRectdv dglRectdv #define glRectf dglRectf #define glRectfv dglRectfv #define glRecti dglRecti #define glRectiv dglRectiv #define glRects dglRects #define glRectsv dglRectsv #define glRenderMode dglRenderMode #define glRotated dglRotated #define glRotatef dglRotatef #define glScaled dglScaled #define glScalef dglScalef #define glScissor dglScissor #define glSelectBuffer dglSelectBuffer #define glShadeModel dglShadeModel #define glStencilFunc dglStencilFunc #define glStencilMask dglStencilMask #define glStencilOp dglStencilOp #define glTexCoord1d dglTexCoord1d #define glTexCoord1dv dglTexCoord1dv #define glTexCoord1f dglTexCoord1f #define glTexCoord1fv dglTexCoord1fv #define glTexCoord1i dglTexCoord1i #define glTexCoord1iv dglTexCoord1iv #define glTexCoord1s dglTexCoord1s #define glTexCoord1sv dglTexCoord1sv #define glTexCoord2d dglTexCoord2d #define glTexCoord2dv dglTexCoord2dv #define glTexCoord2f dglTexCoord2f #define glTexCoord2fv dglTexCoord2fv #define glTexCoord2i dglTexCoord2i #define glTexCoord2iv dglTexCoord2iv #define glTexCoord2s dglTexCoord2s #define glTexCoord2sv dglTexCoord2sv #define glTexCoord3d dglTexCoord3d #define glTexCoord3dv dglTexCoord3dv #define glTexCoord3f dglTexCoord3f #define glTexCoord3fv dglTexCoord3fv #define glTexCoord3i dglTexCoord3i #define glTexCoord3iv dglTexCoord3iv #define glTexCoord3s dglTexCoord3s #define glTexCoord3sv dglTexCoord3sv #define glTexCoord4d dglTexCoord4d #define glTexCoord4dv dglTexCoord4dv #define glTexCoord4f dglTexCoord4f #define glTexCoord4fv dglTexCoord4fv #define glTexCoord4i dglTexCoord4i #define glTexCoord4iv dglTexCoord4iv #define glTexCoord4s dglTexCoord4s #define glTexCoord4sv dglTexCoord4sv #define glTexCoordPointer dglTexCoordPointer #define glTexEnvf dglTexEnvf #define glTexEnvfv dglTexEnvfv #define glTexEnvi dglTexEnvi #define glTexEnviv dglTexEnviv #define glTexGend dglTexGend #define glTexGendv dglTexGendv #define glTexGenf dglTexGenf #define glTexGenfv dglTexGenfv #define glTexGeni dglTexGeni #define glTexGeniv dglTexGeniv #define glTexImage1D dglTexImage1D #define glTexImage2D dglTexImage2D #define glTexParameterf dglTexParameterf #define glTexParameterfv dglTexParameterfv #define glTexParameteri dglTexParameteri #define glTexParameteriv dglTexParameteriv #define glTexSubImage1D dglTexSubImage1D #define glTexSubImage2D dglTexSubImage2D #define glTranslated dglTranslated #define glTranslatef dglTranslatef #define glVertex2d dglVertex2d #define glVertex2dv dglVertex2dv #define glVertex2f dglVertex2f #define glVertex2fv dglVertex2fv #define glVertex2i dglVertex2i #define glVertex2iv dglVertex2iv #define glVertex2s dglVertex2s #define glVertex2sv dglVertex2sv #define glVertex3d dglVertex3d #define glVertex3dv dglVertex3dv #define glVertex3f dglVertex3f #define glVertex3fv dglVertex3fv #define glVertex3i dglVertex3i #define glVertex3iv dglVertex3iv #define glVertex3s dglVertex3s #define glVertex3sv dglVertex3sv #define glVertex4d dglVertex4d #define glVertex4dv dglVertex4dv #define glVertex4f dglVertex4f #define glVertex4fv dglVertex4fv #define glVertex4i dglVertex4i #define glVertex4iv dglVertex4iv #define glVertex4s dglVertex4s #define glVertex4sv dglVertex4sv #define glVertexPointer dglVertexPointer #define glViewport dglViewport #define glMultiTexCoord2fARB dglMultiTexCoord2fARB #define glActiveTextureARB dglActiveTextureARB #define glMultiTexCoord2fSGIS dglMultiTexCoord2fSGIS #define glSelectTextureSGIS dglSelectTextureSGIS #ifdef _WIN32 #define wglCopyContext dwglCopyContext #define wglCreateContext dwglCreateContext #define wglCreateLayerContext dwglCreateLayerContext #define wglDeleteContext dwglDeleteContext #define wglGetCurrentContext dwglGetCurrentContext #define wglGetCurrentDC dwglGetCurrentDC #define wglGetProcAddress dwglGetProcAddress #define wglMakeCurrent dwglMakeCurrent #define wglShareLists dwglShareLists #define wglUseFontBitmapsA dwglUseFontBitmapsA #define wglUseFontBitmapsW dwglUseFontBitmapsW #define wglUseFontOutlinesA dwglUseFontOutlinesA #define wglUseFontOutlinesW dwglUseFontOutlinesW #define wglDescribeLayerPlane dwglDescribeLayerPlane #define wglSetLayerPaletteEntries dwglSetLayerPaletteEntries #define wglGetLayerPaletteEntries dwglGetLayerPaletteEntries #define wglRealizeLayerPalette dwglRealizeLayerPalette #define wglSwapLayerBuffers dwglSwapLayerBuffers #if (WINVER >= 0x0500) #define wglSwapMultipleBuffers dwglSwapMultipleBuffers #endif #endif typedef void (OGLFUNCCALL *glAccum_fp)(GLenum op, GLfloat value); typedef void (OGLFUNCCALL *glAlphaFunc_fp)(GLenum func, GLclampf ref); typedef GLboolean (OGLFUNCCALL *glAreTexturesResident_fp)(GLsizei n, const GLuint *textures, GLboolean *residences); typedef void (OGLFUNCCALL *glArrayElement_fp)(GLint i); typedef void (OGLFUNCCALL *glBegin_fp)(GLenum mode); typedef void (OGLFUNCCALL *glBindTexture_fp)(GLenum target, GLuint texture); typedef void (OGLFUNCCALL *glBitmap_fp)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); typedef void (OGLFUNCCALL *glBlendFunc_fp)(GLenum sfactor, GLenum dfactor); typedef void (OGLFUNCCALL *glCallList_fp)(GLuint list); typedef void (OGLFUNCCALL *glCallLists_fp)(GLsizei n, GLenum type, const GLvoid *lists); typedef void (OGLFUNCCALL *glClear_fp)(GLbitfield mask); typedef void (OGLFUNCCALL *glClearAccum_fp)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (OGLFUNCCALL *glClearColor_fp)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (OGLFUNCCALL *glClearDepth_fp)(GLclampd depth); typedef void (OGLFUNCCALL *glClearIndex_fp)(GLfloat c); typedef void (OGLFUNCCALL *glClearStencil_fp)(GLint s); typedef void (OGLFUNCCALL *glClipPlane_fp)(GLenum plane, const GLdouble *equation); typedef void (OGLFUNCCALL *glColor3b_fp)(GLbyte red, GLbyte green, GLbyte blue); typedef void (OGLFUNCCALL *glColor3bv_fp)(const GLbyte *v); typedef void (OGLFUNCCALL *glColor3d_fp)(GLdouble red, GLdouble green, GLdouble blue); typedef void (OGLFUNCCALL *glColor3dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glColor3f_fp)(GLfloat red, GLfloat green, GLfloat blue); typedef void (OGLFUNCCALL *glColor3fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glColor3i_fp)(GLint red, GLint green, GLint blue); typedef void (OGLFUNCCALL *glColor3iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glColor3s_fp)(GLshort red, GLshort green, GLshort blue); typedef void (OGLFUNCCALL *glColor3sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glColor3ub_fp)(GLubyte red, GLubyte green, GLubyte blue); typedef void (OGLFUNCCALL *glColor3ubv_fp)(const GLubyte *v); typedef void (OGLFUNCCALL *glColor3ui_fp)(GLuint red, GLuint green, GLuint blue); typedef void (OGLFUNCCALL *glColor3uiv_fp)(const GLuint *v); typedef void (OGLFUNCCALL *glColor3us_fp)(GLushort red, GLushort green, GLushort blue); typedef void (OGLFUNCCALL *glColor3usv_fp)(const GLushort *v); typedef void (OGLFUNCCALL *glColor4b_fp)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); typedef void (OGLFUNCCALL *glColor4bv_fp)(const GLbyte *v); typedef void (OGLFUNCCALL *glColor4d_fp)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); typedef void (OGLFUNCCALL *glColor4dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glColor4f_fp)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (OGLFUNCCALL *glColor4fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glColor4i_fp)(GLint red, GLint green, GLint blue, GLint alpha); typedef void (OGLFUNCCALL *glColor4iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glColor4s_fp)(GLshort red, GLshort green, GLshort blue, GLshort alpha); typedef void (OGLFUNCCALL *glColor4sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glColor4ub_fp)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); typedef void (OGLFUNCCALL *glColor4ubv_fp)(const GLubyte *v); typedef void (OGLFUNCCALL *glColor4ui_fp)(GLuint red, GLuint green, GLuint blue, GLuint alpha); typedef void (OGLFUNCCALL *glColor4uiv_fp)(const GLuint *v); typedef void (OGLFUNCCALL *glColor4us_fp)(GLushort red, GLushort green, GLushort blue, GLushort alpha); typedef void (OGLFUNCCALL *glColor4usv_fp)(const GLushort *v); typedef void (OGLFUNCCALL *glColorMask_fp)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (OGLFUNCCALL *glColorMaterial_fp)(GLenum face, GLenum mode); typedef void (OGLFUNCCALL *glColorPointer_fp)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glCopyPixels_fp)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); typedef void (OGLFUNCCALL *glCopyTexImage1D_fp)(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); typedef void (OGLFUNCCALL *glCopyTexImage2D_fp)(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (OGLFUNCCALL *glCopyTexSubImage1D_fp)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (OGLFUNCCALL *glCopyTexSubImage2D_fp)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (OGLFUNCCALL *glCullFace_fp)(GLenum mode); typedef void (OGLFUNCCALL *glDeleteLists_fp)(GLuint list, GLsizei range); typedef void (OGLFUNCCALL *glDeleteTextures_fp)(GLsizei n, const GLuint *textures); typedef void (OGLFUNCCALL *glDepthFunc_fp)(GLenum func); typedef void (OGLFUNCCALL *glDepthMask_fp)(GLboolean flag); typedef void (OGLFUNCCALL *glDepthRange_fp)(GLclampd zNear, GLclampd zFar); typedef void (OGLFUNCCALL *glDisable_fp)(GLenum cap); typedef void (OGLFUNCCALL *glDisableClientState_fp)(GLenum array); typedef void (OGLFUNCCALL *glDrawArrays_fp)(GLenum mode, GLint first, GLsizei count); typedef void (OGLFUNCCALL *glDrawBuffer_fp)(GLenum mode); typedef void (OGLFUNCCALL *glDrawElements_fp)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); typedef void (OGLFUNCCALL *glDrawPixels_fp)(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (OGLFUNCCALL *glEdgeFlag_fp)(GLboolean flag); typedef void (OGLFUNCCALL *glEdgeFlagPointer_fp)(GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glEdgeFlagv_fp)(const GLboolean *flag); typedef void (OGLFUNCCALL *glEnable_fp)(GLenum cap); typedef void (OGLFUNCCALL *glEnableClientState_fp)(GLenum array); typedef void (OGLFUNCCALL *glEnd_fp)(void); typedef void (OGLFUNCCALL *glEndList_fp)(void); typedef void (OGLFUNCCALL *glEvalCoord1d_fp)(GLdouble u); typedef void (OGLFUNCCALL *glEvalCoord1dv_fp)(const GLdouble *u); typedef void (OGLFUNCCALL *glEvalCoord1f_fp)(GLfloat u); typedef void (OGLFUNCCALL *glEvalCoord1fv_fp)(const GLfloat *u); typedef void (OGLFUNCCALL *glEvalCoord2d_fp)(GLdouble u, GLdouble v); typedef void (OGLFUNCCALL *glEvalCoord2dv_fp)(const GLdouble *u); typedef void (OGLFUNCCALL *glEvalCoord2f_fp)(GLfloat u, GLfloat v); typedef void (OGLFUNCCALL *glEvalCoord2fv_fp)(const GLfloat *u); typedef void (OGLFUNCCALL *glEvalMesh1_fp)(GLenum mode, GLint i1, GLint i2); typedef void (OGLFUNCCALL *glEvalMesh2_fp)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); typedef void (OGLFUNCCALL *glEvalPoint1_fp)(GLint i); typedef void (OGLFUNCCALL *glEvalPoint2_fp)(GLint i, GLint j); typedef void (OGLFUNCCALL *glFeedbackBuffer_fp)(GLsizei size, GLenum type, GLfloat *buffer); typedef void (OGLFUNCCALL *glFinish_fp)(void); typedef void (OGLFUNCCALL *glFlush_fp)(void); typedef void (OGLFUNCCALL *glFogf_fp)(GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glFogfv_fp)(GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glFogi_fp)(GLenum pname, GLint param); typedef void (OGLFUNCCALL *glFogiv_fp)(GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glFrontFace_fp)(GLenum mode); typedef void (OGLFUNCCALL *glFrustum_fp)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef GLuint (OGLFUNCCALL *glGenLists_fp)(GLsizei range); typedef void (OGLFUNCCALL *glGenTextures_fp)(GLsizei n, GLuint *textures); typedef void (OGLFUNCCALL *glGetBooleanv_fp)(GLenum pname, GLboolean *params); typedef void (OGLFUNCCALL *glGetClipPlane_fp)(GLenum plane, GLdouble *equation); typedef void (OGLFUNCCALL *glGetDoublev_fp)(GLenum pname, GLdouble *params); typedef GLenum (OGLFUNCCALL *glGetError_fp)(void); typedef void (OGLFUNCCALL *glGetFloatv_fp)(GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetIntegerv_fp)(GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetLightfv_fp)(GLenum light, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetLightiv_fp)(GLenum light, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetMapdv_fp)(GLenum target, GLenum query, GLdouble *v); typedef void (OGLFUNCCALL *glGetMapfv_fp)(GLenum target, GLenum query, GLfloat *v); typedef void (OGLFUNCCALL *glGetMapiv_fp)(GLenum target, GLenum query, GLint *v); typedef void (OGLFUNCCALL *glGetMaterialfv_fp)(GLenum face, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetMaterialiv_fp)(GLenum face, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetPixelMapfv_fp)(GLenum map, GLfloat *values); typedef void (OGLFUNCCALL *glGetPixelMapuiv_fp)(GLenum map, GLuint *values); typedef void (OGLFUNCCALL *glGetPixelMapusv_fp)(GLenum map, GLushort *values); typedef void (OGLFUNCCALL *glGetPointerv_fp)(GLenum pname, GLvoid* *params); typedef void (OGLFUNCCALL *glGetPolygonStipple_fp)(GLubyte *mask); typedef const GLubyte *(OGLFUNCCALL *glGetString_fp)(GLenum name); typedef void (OGLFUNCCALL *glGetTexEnvfv_fp)(GLenum target, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetTexEnviv_fp)(GLenum target, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetTexGendv_fp)(GLenum coord, GLenum pname, GLdouble *params); typedef void (OGLFUNCCALL *glGetTexGenfv_fp)(GLenum coord, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetTexGeniv_fp)(GLenum coord, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetTexImage_fp)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (OGLFUNCCALL *glGetTexLevelParameterfv_fp)(GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetTexLevelParameteriv_fp)(GLenum target, GLint level, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glGetTexParameterfv_fp)(GLenum target, GLenum pname, GLfloat *params); typedef void (OGLFUNCCALL *glGetTexParameteriv_fp)(GLenum target, GLenum pname, GLint *params); typedef void (OGLFUNCCALL *glHint_fp)(GLenum target, GLenum mode); typedef void (OGLFUNCCALL *glIndexMask_fp)(GLuint mask); typedef void (OGLFUNCCALL *glIndexPointer_fp)(GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glIndexd_fp)(GLdouble c); typedef void (OGLFUNCCALL *glIndexdv_fp)(const GLdouble *c); typedef void (OGLFUNCCALL *glIndexf_fp)(GLfloat c); typedef void (OGLFUNCCALL *glIndexfv_fp)(const GLfloat *c); typedef void (OGLFUNCCALL *glIndexi_fp)(GLint c); typedef void (OGLFUNCCALL *glIndexiv_fp)(const GLint *c); typedef void (OGLFUNCCALL *glIndexs_fp)(GLshort c); typedef void (OGLFUNCCALL *glIndexsv_fp)(const GLshort *c); typedef void (OGLFUNCCALL *glIndexub_fp)(GLubyte c); typedef void (OGLFUNCCALL *glIndexubv_fp)(const GLubyte *c); typedef void (OGLFUNCCALL *glInitNames_fp)(void); typedef void (OGLFUNCCALL *glInterleavedArrays_fp)(GLenum format, GLsizei stride, const GLvoid *pointer); typedef GLboolean (OGLFUNCCALL *glIsEnabled_fp)(GLenum cap); typedef GLboolean (OGLFUNCCALL *glIsList_fp)(GLuint list); typedef GLboolean (OGLFUNCCALL *glIsTexture_fp)(GLuint texture); typedef void (OGLFUNCCALL *glLightModelf_fp)(GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glLightModelfv_fp)(GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glLightModeli_fp)(GLenum pname, GLint param); typedef void (OGLFUNCCALL *glLightModeliv_fp)(GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glLightf_fp)(GLenum light, GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glLightfv_fp)(GLenum light, GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glLighti_fp)(GLenum light, GLenum pname, GLint param); typedef void (OGLFUNCCALL *glLightiv_fp)(GLenum light, GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glLineStipple_fp)(GLint factor, GLushort pattern); typedef void (OGLFUNCCALL *glLineWidth_fp)(GLfloat width); typedef void (OGLFUNCCALL *glListBase_fp)(GLuint base); typedef void (OGLFUNCCALL *glLoadIdentity_fp)(void); typedef void (OGLFUNCCALL *glLoadMatrixd_fp)(const GLdouble *m); typedef void (OGLFUNCCALL *glLoadMatrixf_fp)(const GLfloat *m); typedef void (OGLFUNCCALL *glLoadName_fp)(GLuint name); typedef void (OGLFUNCCALL *glLogicOp_fp)(GLenum opcode); typedef void (OGLFUNCCALL *glMap1d_fp)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); typedef void (OGLFUNCCALL *glMap1f_fp)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); typedef void (OGLFUNCCALL *glMap2d_fp)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); typedef void (OGLFUNCCALL *glMap2f_fp)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); typedef void (OGLFUNCCALL *glMapGrid1d_fp)(GLint un, GLdouble u1, GLdouble u2); typedef void (OGLFUNCCALL *glMapGrid1f_fp)(GLint un, GLfloat u1, GLfloat u2); typedef void (OGLFUNCCALL *glMapGrid2d_fp)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); typedef void (OGLFUNCCALL *glMapGrid2f_fp)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); typedef void (OGLFUNCCALL *glMaterialf_fp)(GLenum face, GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glMaterialfv_fp)(GLenum face, GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glMateriali_fp)(GLenum face, GLenum pname, GLint param); typedef void (OGLFUNCCALL *glMaterialiv_fp)(GLenum face, GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glMatrixMode_fp)(GLenum mode); typedef void (OGLFUNCCALL *glMultMatrixd_fp)(const GLdouble *m); typedef void (OGLFUNCCALL *glMultMatrixf_fp)(const GLfloat *m); typedef void (OGLFUNCCALL *glNewList_fp)(GLuint list, GLenum mode); typedef void (OGLFUNCCALL *glNormal3b_fp)(GLbyte nx, GLbyte ny, GLbyte nz); typedef void (OGLFUNCCALL *glNormal3bv_fp)(const GLbyte *v); typedef void (OGLFUNCCALL *glNormal3d_fp)(GLdouble nx, GLdouble ny, GLdouble nz); typedef void (OGLFUNCCALL *glNormal3dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glNormal3f_fp)(GLfloat nx, GLfloat ny, GLfloat nz); typedef void (OGLFUNCCALL *glNormal3fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glNormal3i_fp)(GLint nx, GLint ny, GLint nz); typedef void (OGLFUNCCALL *glNormal3iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glNormal3s_fp)(GLshort nx, GLshort ny, GLshort nz); typedef void (OGLFUNCCALL *glNormal3sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glNormalPointer_fp)(GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glOrtho_fp)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (OGLFUNCCALL *glPassThrough_fp)(GLfloat token); typedef void (OGLFUNCCALL *glPixelMapfv_fp)(GLenum map, GLsizei mapsize, const GLfloat *values); typedef void (OGLFUNCCALL *glPixelMapuiv_fp)(GLenum map, GLsizei mapsize, const GLuint *values); typedef void (OGLFUNCCALL *glPixelMapusv_fp)(GLenum map, GLsizei mapsize, const GLushort *values); typedef void (OGLFUNCCALL *glPixelStoref_fp)(GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glPixelStorei_fp)(GLenum pname, GLint param); typedef void (OGLFUNCCALL *glPixelTransferf_fp)(GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glPixelTransferi_fp)(GLenum pname, GLint param); typedef void (OGLFUNCCALL *glPixelZoom_fp)(GLfloat xfactor, GLfloat yfactor); typedef void (OGLFUNCCALL *glPointSize_fp)(GLfloat size); typedef void (OGLFUNCCALL *glPolygonMode_fp)(GLenum face, GLenum mode); typedef void (OGLFUNCCALL *glPolygonOffset_fp)(GLfloat factor, GLfloat units); typedef void (OGLFUNCCALL *glPolygonStipple_fp)(const GLubyte *mask); typedef void (OGLFUNCCALL *glPopAttrib_fp)(void); typedef void (OGLFUNCCALL *glPopClientAttrib_fp)(void); typedef void (OGLFUNCCALL *glPopMatrix_fp)(void); typedef void (OGLFUNCCALL *glPopName_fp)(void); typedef void (OGLFUNCCALL *glPrioritizeTextures_fp)(GLsizei n, const GLuint *textures, const GLclampf *priorities); typedef void (OGLFUNCCALL *glPushAttrib_fp)(GLbitfield mask); typedef void (OGLFUNCCALL *glPushClientAttrib_fp)(GLbitfield mask); typedef void (OGLFUNCCALL *glPushMatrix_fp)(void); typedef void (OGLFUNCCALL *glPushName_fp)(GLuint name); typedef void (OGLFUNCCALL *glRasterPos2d_fp)(GLdouble x, GLdouble y); typedef void (OGLFUNCCALL *glRasterPos2dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glRasterPos2f_fp)(GLfloat x, GLfloat y); typedef void (OGLFUNCCALL *glRasterPos2fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glRasterPos2i_fp)(GLint x, GLint y); typedef void (OGLFUNCCALL *glRasterPos2iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glRasterPos2s_fp)(GLshort x, GLshort y); typedef void (OGLFUNCCALL *glRasterPos2sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glRasterPos3d_fp)(GLdouble x, GLdouble y, GLdouble z); typedef void (OGLFUNCCALL *glRasterPos3dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glRasterPos3f_fp)(GLfloat x, GLfloat y, GLfloat z); typedef void (OGLFUNCCALL *glRasterPos3fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glRasterPos3i_fp)(GLint x, GLint y, GLint z); typedef void (OGLFUNCCALL *glRasterPos3iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glRasterPos3s_fp)(GLshort x, GLshort y, GLshort z); typedef void (OGLFUNCCALL *glRasterPos3sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glRasterPos4d_fp)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (OGLFUNCCALL *glRasterPos4dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glRasterPos4f_fp)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (OGLFUNCCALL *glRasterPos4fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glRasterPos4i_fp)(GLint x, GLint y, GLint z, GLint w); typedef void (OGLFUNCCALL *glRasterPos4iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glRasterPos4s_fp)(GLshort x, GLshort y, GLshort z, GLshort w); typedef void (OGLFUNCCALL *glRasterPos4sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glReadBuffer_fp)(GLenum mode); typedef void (OGLFUNCCALL *glReadPixels_fp)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); typedef void (OGLFUNCCALL *glRectd_fp)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); typedef void (OGLFUNCCALL *glRectdv_fp)(const GLdouble *v1, const GLdouble *v2); typedef void (OGLFUNCCALL *glRectf_fp)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); typedef void (OGLFUNCCALL *glRectfv_fp)(const GLfloat *v1, const GLfloat *v2); typedef void (OGLFUNCCALL *glRecti_fp)(GLint x1, GLint y1, GLint x2, GLint y2); typedef void (OGLFUNCCALL *glRectiv_fp)(const GLint *v1, const GLint *v2); typedef void (OGLFUNCCALL *glRects_fp)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); typedef void (OGLFUNCCALL *glRectsv_fp)(const GLshort *v1, const GLshort *v2); typedef GLint (OGLFUNCCALL *glRenderMode_fp)(GLenum mode); typedef void (OGLFUNCCALL *glRotated_fp)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (OGLFUNCCALL *glRotatef_fp)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (OGLFUNCCALL *glScaled_fp)(GLdouble x, GLdouble y, GLdouble z); typedef void (OGLFUNCCALL *glScalef_fp)(GLfloat x, GLfloat y, GLfloat z); typedef void (OGLFUNCCALL *glScissor_fp)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (OGLFUNCCALL *glSelectBuffer_fp)(GLsizei size, GLuint *buffer); typedef void (OGLFUNCCALL *glShadeModel_fp)(GLenum mode); typedef void (OGLFUNCCALL *glStencilFunc_fp)(GLenum func, GLint ref, GLuint mask); typedef void (OGLFUNCCALL *glStencilMask_fp)(GLuint mask); typedef void (OGLFUNCCALL *glStencilOp_fp)(GLenum fail, GLenum zfail, GLenum zpass); typedef void (OGLFUNCCALL *glTexCoord1d_fp)(GLdouble s); typedef void (OGLFUNCCALL *glTexCoord1dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glTexCoord1f_fp)(GLfloat s); typedef void (OGLFUNCCALL *glTexCoord1fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glTexCoord1i_fp)(GLint s); typedef void (OGLFUNCCALL *glTexCoord1iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glTexCoord1s_fp)(GLshort s); typedef void (OGLFUNCCALL *glTexCoord1sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glTexCoord2d_fp)(GLdouble s, GLdouble t); typedef void (OGLFUNCCALL *glTexCoord2dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glTexCoord2f_fp)(GLfloat s, GLfloat t); typedef void (OGLFUNCCALL *glTexCoord2fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glTexCoord2i_fp)(GLint s, GLint t); typedef void (OGLFUNCCALL *glTexCoord2iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glTexCoord2s_fp)(GLshort s, GLshort t); typedef void (OGLFUNCCALL *glTexCoord2sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glTexCoord3d_fp)(GLdouble s, GLdouble t, GLdouble r); typedef void (OGLFUNCCALL *glTexCoord3dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glTexCoord3f_fp)(GLfloat s, GLfloat t, GLfloat r); typedef void (OGLFUNCCALL *glTexCoord3fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glTexCoord3i_fp)(GLint s, GLint t, GLint r); typedef void (OGLFUNCCALL *glTexCoord3iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glTexCoord3s_fp)(GLshort s, GLshort t, GLshort r); typedef void (OGLFUNCCALL *glTexCoord3sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glTexCoord4d_fp)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (OGLFUNCCALL *glTexCoord4dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glTexCoord4f_fp)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (OGLFUNCCALL *glTexCoord4fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glTexCoord4i_fp)(GLint s, GLint t, GLint r, GLint q); typedef void (OGLFUNCCALL *glTexCoord4iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glTexCoord4s_fp)(GLshort s, GLshort t, GLshort r, GLshort q); typedef void (OGLFUNCCALL *glTexCoord4sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glTexCoordPointer_fp)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glTexEnvf_fp)(GLenum target, GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glTexEnvfv_fp)(GLenum target, GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glTexEnvi_fp)(GLenum target, GLenum pname, GLint param); typedef void (OGLFUNCCALL *glTexEnviv_fp)(GLenum target, GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glTexGend_fp)(GLenum coord, GLenum pname, GLdouble param); typedef void (OGLFUNCCALL *glTexGendv_fp)(GLenum coord, GLenum pname, const GLdouble *params); typedef void (OGLFUNCCALL *glTexGenf_fp)(GLenum coord, GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glTexGenfv_fp)(GLenum coord, GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glTexGeni_fp)(GLenum coord, GLenum pname, GLint param); typedef void (OGLFUNCCALL *glTexGeniv_fp)(GLenum coord, GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glTexImage1D_fp)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (OGLFUNCCALL *glTexImage2D_fp)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (OGLFUNCCALL *glTexParameterf_fp)(GLenum target, GLenum pname, GLfloat param); typedef void (OGLFUNCCALL *glTexParameterfv_fp)(GLenum target, GLenum pname, const GLfloat *params); typedef void (OGLFUNCCALL *glTexParameteri_fp)(GLenum target, GLenum pname, GLint param); typedef void (OGLFUNCCALL *glTexParameteriv_fp)(GLenum target, GLenum pname, const GLint *params); typedef void (OGLFUNCCALL *glTexSubImage1D_fp)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (OGLFUNCCALL *glTexSubImage2D_fp)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (OGLFUNCCALL *glTranslated_fp)(GLdouble x, GLdouble y, GLdouble z); typedef void (OGLFUNCCALL *glTranslatef_fp)(GLfloat x, GLfloat y, GLfloat z); typedef void (OGLFUNCCALL *glVertex2d_fp)(GLdouble x, GLdouble y); typedef void (OGLFUNCCALL *glVertex2dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glVertex2f_fp)(GLfloat x, GLfloat y); typedef void (OGLFUNCCALL *glVertex2fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glVertex2i_fp)(GLint x, GLint y); typedef void (OGLFUNCCALL *glVertex2iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glVertex2s_fp)(GLshort x, GLshort y); typedef void (OGLFUNCCALL *glVertex2sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glVertex3d_fp)(GLdouble x, GLdouble y, GLdouble z); typedef void (OGLFUNCCALL *glVertex3dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glVertex3f_fp)(GLfloat x, GLfloat y, GLfloat z); typedef void (OGLFUNCCALL *glVertex3fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glVertex3i_fp)(GLint x, GLint y, GLint z); typedef void (OGLFUNCCALL *glVertex3iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glVertex3s_fp)(GLshort x, GLshort y, GLshort z); typedef void (OGLFUNCCALL *glVertex3sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glVertex4d_fp)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (OGLFUNCCALL *glVertex4dv_fp)(const GLdouble *v); typedef void (OGLFUNCCALL *glVertex4f_fp)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (OGLFUNCCALL *glVertex4fv_fp)(const GLfloat *v); typedef void (OGLFUNCCALL *glVertex4i_fp)(GLint x, GLint y, GLint z, GLint w); typedef void (OGLFUNCCALL *glVertex4iv_fp)(const GLint *v); typedef void (OGLFUNCCALL *glVertex4s_fp)(GLshort x, GLshort y, GLshort z, GLshort w); typedef void (OGLFUNCCALL *glVertex4sv_fp)(const GLshort *v); typedef void (OGLFUNCCALL *glVertexPointer_fp)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (OGLFUNCCALL *glViewport_fp)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (OGLFUNCCALL *glMultiTexCoord2fARB_fp)(GLenum target, GLfloat s, GLfloat t); typedef void (OGLFUNCCALL *glActiveTextureARB_fp)(GLenum target); typedef void (OGLFUNCCALL *glMultiTexCoord2fSGIS_fp)(GLenum target, GLfloat s, GLfloat t); typedef void (OGLFUNCCALL *glSelectTextureSGIS_fp)(GLenum target); #ifdef _WIN32 typedef BOOL (OGLFUNCCALL *wglCopyContext_fp)(HGLRC, HGLRC, UINT); typedef HGLRC (OGLFUNCCALL *wglCreateContext_fp)(HDC); typedef HGLRC (OGLFUNCCALL *wglCreateLayerContext_fp)(HDC, int); typedef BOOL (OGLFUNCCALL *wglDeleteContext_fp)(HGLRC); typedef HGLRC (OGLFUNCCALL *wglGetCurrentContext_fp)(VOID); typedef HDC (OGLFUNCCALL *wglGetCurrentDC_fp)(VOID); typedef PROC (OGLFUNCCALL *wglGetProcAddress_fp)(LPCSTR); typedef BOOL (OGLFUNCCALL *wglMakeCurrent_fp)(HDC, HGLRC); typedef BOOL (OGLFUNCCALL *wglShareLists_fp)(HGLRC, HGLRC); typedef BOOL (OGLFUNCCALL *wglUseFontBitmapsA_fp)(HDC, DWORD, DWORD, DWORD); typedef BOOL (OGLFUNCCALL *wglUseFontBitmapsW_fp)(HDC, DWORD, DWORD, DWORD); typedef BOOL (OGLFUNCCALL *wglUseFontOutlinesA_fp)(HDC, DWORD, DWORD, DWORD, FLOAT,FLOAT, int, LPGLYPHMETRICSFLOAT); typedef BOOL (OGLFUNCCALL *wglUseFontOutlinesW_fp)(HDC, DWORD, DWORD, DWORD, FLOAT,FLOAT, int, LPGLYPHMETRICSFLOAT); typedef BOOL (OGLFUNCCALL *wglDescribeLayerPlane_fp)(HDC, int, int, UINT,LPLAYERPLANEDESCRIPTOR); typedef int (OGLFUNCCALL *wglSetLayerPaletteEntries_fp)(HDC, int, int, int,CONST COLORREF *); typedef int (OGLFUNCCALL *wglGetLayerPaletteEntries_fp)(HDC, int, int, int,COLORREF *); typedef BOOL (OGLFUNCCALL *wglRealizeLayerPalette_fp)(HDC, int, BOOL); typedef BOOL (OGLFUNCCALL *wglSwapLayerBuffers_fp)(HDC, UINT); #if (WINVER >= 0x0500) typedef DWORD (OGLFUNCCALL *wglSwapMultipleBuffers_fp)(UINT, CONST WGLSWAP *); #endif #endif DEFVAR glAccum_fp dglAccum; DEFVAR glAlphaFunc_fp dglAlphaFunc; DEFVAR glAreTexturesResident_fp dglAreTexturesResident; DEFVAR glArrayElement_fp dglArrayElement; DEFVAR glBegin_fp dglBegin; DEFVAR glBindTexture_fp dglBindTexture; DEFVAR glBitmap_fp dglBitmap; DEFVAR glBlendFunc_fp dglBlendFunc; DEFVAR glCallList_fp dglCallList; DEFVAR glCallLists_fp dglCallLists; DEFVAR glClear_fp dglClear; DEFVAR glClearAccum_fp dglClearAccum; DEFVAR glClearColor_fp dglClearColor; DEFVAR glClearDepth_fp dglClearDepth; DEFVAR glClearIndex_fp dglClearIndex; DEFVAR glClearStencil_fp dglClearStencil; DEFVAR glClipPlane_fp dglClipPlane; DEFVAR glColor3b_fp dglColor3b; DEFVAR glColor3bv_fp dglColor3bv; DEFVAR glColor3d_fp dglColor3d; DEFVAR glColor3dv_fp dglColor3dv; DEFVAR glColor3f_fp dglColor3f; DEFVAR glColor3fv_fp dglColor3fv; DEFVAR glColor3i_fp dglColor3i; DEFVAR glColor3iv_fp dglColor3iv; DEFVAR glColor3s_fp dglColor3s; DEFVAR glColor3sv_fp dglColor3sv; DEFVAR glColor3ub_fp dglColor3ub; DEFVAR glColor3ubv_fp dglColor3ubv; DEFVAR glColor3ui_fp dglColor3ui; DEFVAR glColor3uiv_fp dglColor3uiv; DEFVAR glColor3us_fp dglColor3us; DEFVAR glColor3usv_fp dglColor3usv; DEFVAR glColor4b_fp dglColor4b; DEFVAR glColor4bv_fp dglColor4bv; DEFVAR glColor4d_fp dglColor4d; DEFVAR glColor4dv_fp dglColor4dv; DEFVAR glColor4f_fp dglColor4f; DEFVAR glColor4fv_fp dglColor4fv; DEFVAR glColor4i_fp dglColor4i; DEFVAR glColor4iv_fp dglColor4iv; DEFVAR glColor4s_fp dglColor4s; DEFVAR glColor4sv_fp dglColor4sv; DEFVAR glColor4ub_fp dglColor4ub; DEFVAR glColor4ubv_fp dglColor4ubv; DEFVAR glColor4ui_fp dglColor4ui; DEFVAR glColor4uiv_fp dglColor4uiv; DEFVAR glColor4us_fp dglColor4us; DEFVAR glColor4usv_fp dglColor4usv; DEFVAR glColorMask_fp dglColorMask; DEFVAR glColorMaterial_fp dglColorMaterial; DEFVAR glColorPointer_fp dglColorPointer; DEFVAR glCopyPixels_fp dglCopyPixels; DEFVAR glCopyTexImage1D_fp dglCopyTexImage1D; DEFVAR glCopyTexImage2D_fp dglCopyTexImage2D; DEFVAR glCopyTexSubImage1D_fp dglCopyTexSubImage1D; DEFVAR glCopyTexSubImage2D_fp dglCopyTexSubImage2D; DEFVAR glCullFace_fp dglCullFace; DEFVAR glDeleteLists_fp dglDeleteLists; DEFVAR glDeleteTextures_fp dglDeleteTextures; DEFVAR glDepthFunc_fp dglDepthFunc; DEFVAR glDepthMask_fp dglDepthMask; DEFVAR glDepthRange_fp dglDepthRange; DEFVAR glDisable_fp dglDisable; DEFVAR glDisableClientState_fp dglDisableClientState; DEFVAR glDrawArrays_fp dglDrawArrays; DEFVAR glDrawBuffer_fp dglDrawBuffer; DEFVAR glDrawElements_fp dglDrawElements; DEFVAR glDrawPixels_fp dglDrawPixels; DEFVAR glEdgeFlag_fp dglEdgeFlag; DEFVAR glEdgeFlagPointer_fp dglEdgeFlagPointer; DEFVAR glEdgeFlagv_fp dglEdgeFlagv; DEFVAR glEnable_fp dglEnable; DEFVAR glEnableClientState_fp dglEnableClientState; DEFVAR glEnd_fp dglEnd; DEFVAR glEndList_fp dglEndList; DEFVAR glEvalCoord1d_fp dglEvalCoord1d; DEFVAR glEvalCoord1dv_fp dglEvalCoord1dv; DEFVAR glEvalCoord1f_fp dglEvalCoord1f; DEFVAR glEvalCoord1fv_fp dglEvalCoord1fv; DEFVAR glEvalCoord2d_fp dglEvalCoord2d; DEFVAR glEvalCoord2dv_fp dglEvalCoord2dv; DEFVAR glEvalCoord2f_fp dglEvalCoord2f; DEFVAR glEvalCoord2fv_fp dglEvalCoord2fv; DEFVAR glEvalMesh1_fp dglEvalMesh1; DEFVAR glEvalMesh2_fp dglEvalMesh2; DEFVAR glEvalPoint1_fp dglEvalPoint1; DEFVAR glEvalPoint2_fp dglEvalPoint2; DEFVAR glFeedbackBuffer_fp dglFeedbackBuffer; DEFVAR glFinish_fp dglFinish; DEFVAR glFlush_fp dglFlush; DEFVAR glFogf_fp dglFogf; DEFVAR glFogfv_fp dglFogfv; DEFVAR glFogi_fp dglFogi; DEFVAR glFogiv_fp dglFogiv; DEFVAR glFrontFace_fp dglFrontFace; DEFVAR glFrustum_fp dglFrustum; DEFVAR glGenLists_fp dglGenLists; DEFVAR glGenTextures_fp dglGenTextures; DEFVAR glGetBooleanv_fp dglGetBooleanv; DEFVAR glGetClipPlane_fp dglGetClipPlane; DEFVAR glGetDoublev_fp dglGetDoublev; DEFVAR glGetError_fp dglGetError; DEFVAR glGetFloatv_fp dglGetFloatv; DEFVAR glGetIntegerv_fp dglGetIntegerv; DEFVAR glGetLightfv_fp dglGetLightfv; DEFVAR glGetLightiv_fp dglGetLightiv; DEFVAR glGetMapdv_fp dglGetMapdv; DEFVAR glGetMapfv_fp dglGetMapfv; DEFVAR glGetMapiv_fp dglGetMapiv; DEFVAR glGetMaterialfv_fp dglGetMaterialfv; DEFVAR glGetMaterialiv_fp dglGetMaterialiv; DEFVAR glGetPixelMapfv_fp dglGetPixelMapfv; DEFVAR glGetPixelMapuiv_fp dglGetPixelMapuiv; DEFVAR glGetPixelMapusv_fp dglGetPixelMapusv; DEFVAR glGetPointerv_fp dglGetPointerv; DEFVAR glGetPolygonStipple_fp dglGetPolygonStipple; DEFVAR glGetString_fp dglGetString; DEFVAR glGetTexEnvfv_fp dglGetTexEnvfv; DEFVAR glGetTexEnviv_fp dglGetTexEnviv; DEFVAR glGetTexGendv_fp dglGetTexGendv; DEFVAR glGetTexGenfv_fp dglGetTexGenfv; DEFVAR glGetTexGeniv_fp dglGetTexGeniv; DEFVAR glGetTexImage_fp dglGetTexImage; DEFVAR glGetTexLevelParameterfv_fp dglGetTexLevelParameterfv; DEFVAR glGetTexLevelParameteriv_fp dglGetTexLevelParameteriv; DEFVAR glGetTexParameterfv_fp dglGetTexParameterfv; DEFVAR glGetTexParameteriv_fp dglGetTexParameteriv; DEFVAR glHint_fp dglHint; DEFVAR glIndexMask_fp dglIndexMask; DEFVAR glIndexPointer_fp dglIndexPointer; DEFVAR glIndexd_fp dglIndexd; DEFVAR glIndexdv_fp dglIndexdv; DEFVAR glIndexf_fp dglIndexf; DEFVAR glIndexfv_fp dglIndexfv; DEFVAR glIndexi_fp dglIndexi; DEFVAR glIndexiv_fp dglIndexiv; DEFVAR glIndexs_fp dglIndexs; DEFVAR glIndexsv_fp dglIndexsv; DEFVAR glIndexub_fp dglIndexub; DEFVAR glIndexubv_fp dglIndexubv; DEFVAR glInitNames_fp dglInitNames; DEFVAR glInterleavedArrays_fp dglInterleavedArrays; DEFVAR glIsEnabled_fp dglIsEnabled; DEFVAR glIsList_fp dglIsList; DEFVAR glIsTexture_fp dglIsTexture; DEFVAR glLightModelf_fp dglLightModelf; DEFVAR glLightModelfv_fp dglLightModelfv; DEFVAR glLightModeli_fp dglLightModeli; DEFVAR glLightModeliv_fp dglLightModeliv; DEFVAR glLightf_fp dglLightf; DEFVAR glLightfv_fp dglLightfv; DEFVAR glLighti_fp dglLighti; DEFVAR glLightiv_fp dglLightiv; DEFVAR glLineStipple_fp dglLineStipple; DEFVAR glLineWidth_fp dglLineWidth; DEFVAR glListBase_fp dglListBase; DEFVAR glLoadIdentity_fp dglLoadIdentity; DEFVAR glLoadMatrixd_fp dglLoadMatrixd; DEFVAR glLoadMatrixf_fp dglLoadMatrixf; DEFVAR glLoadName_fp dglLoadName; DEFVAR glLogicOp_fp dglLogicOp; DEFVAR glMap1d_fp dglMap1d; DEFVAR glMap1f_fp dglMap1f; DEFVAR glMap2d_fp dglMap2d; DEFVAR glMap2f_fp dglMap2f; DEFVAR glMapGrid1d_fp dglMapGrid1d; DEFVAR glMapGrid1f_fp dglMapGrid1f; DEFVAR glMapGrid2d_fp dglMapGrid2d; DEFVAR glMapGrid2f_fp dglMapGrid2f; DEFVAR glMaterialf_fp dglMaterialf; DEFVAR glMaterialfv_fp dglMaterialfv; DEFVAR glMateriali_fp dglMateriali; DEFVAR glMaterialiv_fp dglMaterialiv; DEFVAR glMatrixMode_fp dglMatrixMode; DEFVAR glMultMatrixd_fp dglMultMatrixd; DEFVAR glMultMatrixf_fp dglMultMatrixf; DEFVAR glNewList_fp dglNewList; DEFVAR glNormal3b_fp dglNormal3b; DEFVAR glNormal3bv_fp dglNormal3bv; DEFVAR glNormal3d_fp dglNormal3d; DEFVAR glNormal3dv_fp dglNormal3dv; DEFVAR glNormal3f_fp dglNormal3f; DEFVAR glNormal3fv_fp dglNormal3fv; DEFVAR glNormal3i_fp dglNormal3i; DEFVAR glNormal3iv_fp dglNormal3iv; DEFVAR glNormal3s_fp dglNormal3s; DEFVAR glNormal3sv_fp dglNormal3sv; DEFVAR glNormalPointer_fp dglNormalPointer; DEFVAR glOrtho_fp dglOrtho; DEFVAR glPassThrough_fp dglPassThrough; DEFVAR glPixelMapfv_fp dglPixelMapfv; DEFVAR glPixelMapuiv_fp dglPixelMapuiv; DEFVAR glPixelMapusv_fp dglPixelMapusv; DEFVAR glPixelStoref_fp dglPixelStoref; DEFVAR glPixelStorei_fp dglPixelStorei; DEFVAR glPixelTransferf_fp dglPixelTransferf; DEFVAR glPixelTransferi_fp dglPixelTransferi; DEFVAR glPixelZoom_fp dglPixelZoom; DEFVAR glPointSize_fp dglPointSize; DEFVAR glPolygonMode_fp dglPolygonMode; DEFVAR glPolygonOffset_fp dglPolygonOffset; DEFVAR glPolygonStipple_fp dglPolygonStipple; DEFVAR glPopAttrib_fp dglPopAttrib; DEFVAR glPopClientAttrib_fp dglPopClientAttrib; DEFVAR glPopMatrix_fp dglPopMatrix; DEFVAR glPopName_fp dglPopName; DEFVAR glPrioritizeTextures_fp dglPrioritizeTextures; DEFVAR glPushAttrib_fp dglPushAttrib; DEFVAR glPushClientAttrib_fp dglPushClientAttrib; DEFVAR glPushMatrix_fp dglPushMatrix; DEFVAR glPushName_fp dglPushName; DEFVAR glRasterPos2d_fp dglRasterPos2d; DEFVAR glRasterPos2dv_fp dglRasterPos2dv; DEFVAR glRasterPos2f_fp dglRasterPos2f; DEFVAR glRasterPos2fv_fp dglRasterPos2fv; DEFVAR glRasterPos2i_fp dglRasterPos2i; DEFVAR glRasterPos2iv_fp dglRasterPos2iv; DEFVAR glRasterPos2s_fp dglRasterPos2s; DEFVAR glRasterPos2sv_fp dglRasterPos2sv; DEFVAR glRasterPos3d_fp dglRasterPos3d; DEFVAR glRasterPos3dv_fp dglRasterPos3dv; DEFVAR glRasterPos3f_fp dglRasterPos3f; DEFVAR glRasterPos3fv_fp dglRasterPos3fv; DEFVAR glRasterPos3i_fp dglRasterPos3i; DEFVAR glRasterPos3iv_fp dglRasterPos3iv; DEFVAR glRasterPos3s_fp dglRasterPos3s; DEFVAR glRasterPos3sv_fp dglRasterPos3sv; DEFVAR glRasterPos4d_fp dglRasterPos4d; DEFVAR glRasterPos4dv_fp dglRasterPos4dv; DEFVAR glRasterPos4f_fp dglRasterPos4f; DEFVAR glRasterPos4fv_fp dglRasterPos4fv; DEFVAR glRasterPos4i_fp dglRasterPos4i; DEFVAR glRasterPos4iv_fp dglRasterPos4iv; DEFVAR glRasterPos4s_fp dglRasterPos4s; DEFVAR glRasterPos4sv_fp dglRasterPos4sv; DEFVAR glReadBuffer_fp dglReadBuffer; DEFVAR glReadPixels_fp dglReadPixels; DEFVAR glRectd_fp dglRectd; DEFVAR glRectdv_fp dglRectdv; DEFVAR glRectf_fp dglRectf; DEFVAR glRectfv_fp dglRectfv; DEFVAR glRecti_fp dglRecti; DEFVAR glRectiv_fp dglRectiv; DEFVAR glRects_fp dglRects; DEFVAR glRectsv_fp dglRectsv; DEFVAR glRenderMode_fp dglRenderMode; DEFVAR glRotated_fp dglRotated; DEFVAR glRotatef_fp dglRotatef; DEFVAR glScaled_fp dglScaled; DEFVAR glScalef_fp dglScalef; DEFVAR glScissor_fp dglScissor; DEFVAR glSelectBuffer_fp dglSelectBuffer; DEFVAR glShadeModel_fp dglShadeModel; DEFVAR glStencilFunc_fp dglStencilFunc; DEFVAR glStencilMask_fp dglStencilMask; DEFVAR glStencilOp_fp dglStencilOp; DEFVAR glTexCoord1d_fp dglTexCoord1d; DEFVAR glTexCoord1dv_fp dglTexCoord1dv; DEFVAR glTexCoord1f_fp dglTexCoord1f; DEFVAR glTexCoord1fv_fp dglTexCoord1fv; DEFVAR glTexCoord1i_fp dglTexCoord1i; DEFVAR glTexCoord1iv_fp dglTexCoord1iv; DEFVAR glTexCoord1s_fp dglTexCoord1s; DEFVAR glTexCoord1sv_fp dglTexCoord1sv; DEFVAR glTexCoord2d_fp dglTexCoord2d; DEFVAR glTexCoord2dv_fp dglTexCoord2dv; DEFVAR glTexCoord2f_fp dglTexCoord2f; DEFVAR glTexCoord2fv_fp dglTexCoord2fv; DEFVAR glTexCoord2i_fp dglTexCoord2i; DEFVAR glTexCoord2iv_fp dglTexCoord2iv; DEFVAR glTexCoord2s_fp dglTexCoord2s; DEFVAR glTexCoord2sv_fp dglTexCoord2sv; DEFVAR glTexCoord3d_fp dglTexCoord3d; DEFVAR glTexCoord3dv_fp dglTexCoord3dv; DEFVAR glTexCoord3f_fp dglTexCoord3f; DEFVAR glTexCoord3fv_fp dglTexCoord3fv; DEFVAR glTexCoord3i_fp dglTexCoord3i; DEFVAR glTexCoord3iv_fp dglTexCoord3iv; DEFVAR glTexCoord3s_fp dglTexCoord3s; DEFVAR glTexCoord3sv_fp dglTexCoord3sv; DEFVAR glTexCoord4d_fp dglTexCoord4d; DEFVAR glTexCoord4dv_fp dglTexCoord4dv; DEFVAR glTexCoord4f_fp dglTexCoord4f; DEFVAR glTexCoord4fv_fp dglTexCoord4fv; DEFVAR glTexCoord4i_fp dglTexCoord4i; DEFVAR glTexCoord4iv_fp dglTexCoord4iv; DEFVAR glTexCoord4s_fp dglTexCoord4s; DEFVAR glTexCoord4sv_fp dglTexCoord4sv; DEFVAR glTexCoordPointer_fp dglTexCoordPointer; DEFVAR glTexEnvf_fp dglTexEnvf; DEFVAR glTexEnvfv_fp dglTexEnvfv; DEFVAR glTexEnvi_fp dglTexEnvi; DEFVAR glTexEnviv_fp dglTexEnviv; DEFVAR glTexGend_fp dglTexGend; DEFVAR glTexGendv_fp dglTexGendv; DEFVAR glTexGenf_fp dglTexGenf; DEFVAR glTexGenfv_fp dglTexGenfv; DEFVAR glTexGeni_fp dglTexGeni; DEFVAR glTexGeniv_fp dglTexGeniv; DEFVAR glTexImage1D_fp dglTexImage1D; DEFVAR glTexImage2D_fp dglTexImage2D; DEFVAR glTexParameterf_fp dglTexParameterf; DEFVAR glTexParameterfv_fp dglTexParameterfv; DEFVAR glTexParameteri_fp dglTexParameteri; DEFVAR glTexParameteriv_fp dglTexParameteriv; DEFVAR glTexSubImage1D_fp dglTexSubImage1D; DEFVAR glTexSubImage2D_fp dglTexSubImage2D; DEFVAR glTranslated_fp dglTranslated; DEFVAR glTranslatef_fp dglTranslatef; DEFVAR glVertex2d_fp dglVertex2d; DEFVAR glVertex2dv_fp dglVertex2dv; DEFVAR glVertex2f_fp dglVertex2f; DEFVAR glVertex2fv_fp dglVertex2fv; DEFVAR glVertex2i_fp dglVertex2i; DEFVAR glVertex2iv_fp dglVertex2iv; DEFVAR glVertex2s_fp dglVertex2s; DEFVAR glVertex2sv_fp dglVertex2sv; DEFVAR glVertex3d_fp dglVertex3d; DEFVAR glVertex3dv_fp dglVertex3dv; DEFVAR glVertex3f_fp dglVertex3f; DEFVAR glVertex3fv_fp dglVertex3fv; DEFVAR glVertex3i_fp dglVertex3i; DEFVAR glVertex3iv_fp dglVertex3iv; DEFVAR glVertex3s_fp dglVertex3s; DEFVAR glVertex3sv_fp dglVertex3sv; DEFVAR glVertex4d_fp dglVertex4d; DEFVAR glVertex4dv_fp dglVertex4dv; DEFVAR glVertex4f_fp dglVertex4f; DEFVAR glVertex4fv_fp dglVertex4fv; DEFVAR glVertex4i_fp dglVertex4i; DEFVAR glVertex4iv_fp dglVertex4iv; DEFVAR glVertex4s_fp dglVertex4s; DEFVAR glVertex4sv_fp dglVertex4sv; DEFVAR glVertexPointer_fp dglVertexPointer; DEFVAR glViewport_fp dglViewport; DEFVAR glMultiTexCoord2fARB_fp dglMultiTexCoord2fARB; DEFVAR glActiveTextureARB_fp dglActiveTextureARB; DEFVAR glMultiTexCoord2fSGIS_fp dglMultiTexCoord2fSGIS; DEFVAR glSelectTextureSGIS_fp dglSelectTextureSGIS; #ifdef _WIN32 DEFVAR wglCopyContext_fp dwglCopyContext; DEFVAR wglCreateContext_fp dwglCreateContext; DEFVAR wglCreateLayerContext_fp dwglCreateLayerContext; DEFVAR wglDeleteContext_fp dwglDeleteContext; DEFVAR wglGetCurrentContext_fp dwglGetCurrentContext; DEFVAR wglGetCurrentDC_fp dwglGetCurrentDC; DEFVAR wglGetProcAddress_fp dwglGetProcAddress; DEFVAR wglMakeCurrent_fp dwglMakeCurrent; DEFVAR wglShareLists_fp dwglShareLists; DEFVAR wglUseFontBitmapsA_fp dwglUseFontBitmapsA; DEFVAR wglUseFontBitmapsW_fp dwglUseFontBitmapsW; DEFVAR wglUseFontOutlinesA_fp dwglUseFontOutlinesA; DEFVAR wglUseFontOutlinesW_fp dwglUseFontOutlinesW; DEFVAR wglDescribeLayerPlane_fp dwglDescribeLayerPlane; DEFVAR wglSetLayerPaletteEntries_fp dwglSetLayerPaletteEntries; DEFVAR wglGetLayerPaletteEntries_fp dwglGetLayerPaletteEntries; DEFVAR wglRealizeLayerPalette_fp dwglRealizeLayerPalette; DEFVAR wglSwapLayerBuffers_fp dwglSwapLayerBuffers; #if (WINVER >= 0x0500) DEFVAR wglSwapMultipleBuffers_fp dwglSwapMultipleBuffers; #endif #endif #ifdef DECLARE_VARS // Dynamic module load functions #ifdef _WIN32 void *dll_LoadModule(const char *name) { HINSTANCE handle; handle = LoadLibrary(name); return (void *)handle; } void dll_UnloadModule(void *hdl) { HINSTANCE handle; handle = (HINSTANCE)hdl; if(hdl) { FreeLibrary(handle); } } void *dll_GetSymbol(void *dllhandle,const char *symname) { if(!dllhandle) return NULL; return (void *)GetProcAddress((HINSTANCE)dllhandle,symname); } #endif #ifdef __LINUX__ #include void *dll_LoadModule(const char *name) { return (void *)dlopen(name,RTLD_NOW|RTLD_GLOBAL); } void dll_UnloadModule(void *hdl) { if(hdl) { dlclose(hdl); } } void *dll_GetSymbol(void *dllhandle,const char *symname) { if(!dllhandle) return NULL; return dlsym(dllhandle,symname); } #endif #endif //DECLARE_VARS void OpenGL_SetFuncsToNull(void); extern char *OglLibPath; #ifndef DECLARE_VARS // pass true to load the library // pass false to unload it bool OpenGL_LoadLibrary(bool load);//load=true removed because not c++ #else void *OpenGLModuleHandle=NULL; //char *OglLibPath="opengl32.dll"; bool OpenGL_LoadLibrary(bool load) { if(load && OpenGLModuleHandle) return true; OpenGL_SetFuncsToNull(); if(!load) { if(OpenGLModuleHandle) { dll_UnloadModule(OpenGLModuleHandle); OpenGLModuleHandle = NULL; } return true; }else { OpenGLModuleHandle = dll_LoadModule(OglLibPath); if(!OpenGLModuleHandle) return false; dglAccum = (glAccum_fp)dll_GetSymbol(OpenGLModuleHandle,"glAccum"); dglAlphaFunc = (glAlphaFunc_fp)dll_GetSymbol(OpenGLModuleHandle,"glAlphaFunc"); dglAreTexturesResident = (glAreTexturesResident_fp)dll_GetSymbol(OpenGLModuleHandle,"glAreTexturesResident"); dglArrayElement = (glArrayElement_fp)dll_GetSymbol(OpenGLModuleHandle,"glArrayElement"); dglBegin = (glBegin_fp)dll_GetSymbol(OpenGLModuleHandle,"glBegin"); dglBindTexture = (glBindTexture_fp)dll_GetSymbol(OpenGLModuleHandle,"glBindTexture"); dglBitmap = (glBitmap_fp)dll_GetSymbol(OpenGLModuleHandle,"glBitmap"); dglBlendFunc = (glBlendFunc_fp)dll_GetSymbol(OpenGLModuleHandle,"glBlendFunc"); dglCallList = (glCallList_fp)dll_GetSymbol(OpenGLModuleHandle,"glCallList"); dglCallLists = (glCallLists_fp)dll_GetSymbol(OpenGLModuleHandle,"glCallLists"); dglClear = (glClear_fp)dll_GetSymbol(OpenGLModuleHandle,"glClear"); dglClearAccum = (glClearAccum_fp)dll_GetSymbol(OpenGLModuleHandle,"glClearAccum"); dglClearColor = (glClearColor_fp)dll_GetSymbol(OpenGLModuleHandle,"glClearColor"); dglClearDepth = (glClearDepth_fp)dll_GetSymbol(OpenGLModuleHandle,"glClearDepth"); dglClearIndex = (glClearIndex_fp)dll_GetSymbol(OpenGLModuleHandle,"glClearIndex"); dglClearStencil = (glClearStencil_fp)dll_GetSymbol(OpenGLModuleHandle,"glClearStencil"); dglClipPlane = (glClipPlane_fp)dll_GetSymbol(OpenGLModuleHandle,"glClipPlane"); dglColor3b = (glColor3b_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3b"); dglColor3bv = (glColor3bv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3bv"); dglColor3d = (glColor3d_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3d"); dglColor3dv = (glColor3dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3dv"); dglColor3f = (glColor3f_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3f"); dglColor3fv = (glColor3fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3fv"); dglColor3i = (glColor3i_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3i"); dglColor3iv = (glColor3iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3iv"); dglColor3s = (glColor3s_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3s"); dglColor3sv = (glColor3sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3sv"); dglColor3ub = (glColor3ub_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3ub"); dglColor3ubv = (glColor3ubv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3ubv"); dglColor3ui = (glColor3ui_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3ui"); dglColor3uiv = (glColor3uiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3uiv"); dglColor3us = (glColor3us_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3us"); dglColor3usv = (glColor3usv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor3usv"); dglColor4b = (glColor4b_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4b"); dglColor4bv = (glColor4bv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4bv"); dglColor4d = (glColor4d_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4d"); dglColor4dv = (glColor4dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4dv"); dglColor4f = (glColor4f_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4f"); dglColor4fv = (glColor4fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4fv"); dglColor4i = (glColor4i_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4i"); dglColor4iv = (glColor4iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4iv"); dglColor4s = (glColor4s_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4s"); dglColor4sv = (glColor4sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4sv"); dglColor4ub = (glColor4ub_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4ub"); dglColor4ubv = (glColor4ubv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4ubv"); dglColor4ui = (glColor4ui_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4ui"); dglColor4uiv = (glColor4uiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4uiv"); dglColor4us = (glColor4us_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4us"); dglColor4usv = (glColor4usv_fp)dll_GetSymbol(OpenGLModuleHandle,"glColor4usv"); dglColorMask = (glColorMask_fp)dll_GetSymbol(OpenGLModuleHandle,"glColorMask"); dglColorMaterial = (glColorMaterial_fp)dll_GetSymbol(OpenGLModuleHandle,"glColorMaterial"); dglColorPointer = (glColorPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glColorPointer"); dglCopyPixels = (glCopyPixels_fp)dll_GetSymbol(OpenGLModuleHandle,"glCopyPixels"); dglCopyTexImage1D = (glCopyTexImage1D_fp)dll_GetSymbol(OpenGLModuleHandle,"glCopyTexImage1D"); dglCopyTexImage2D = (glCopyTexImage2D_fp)dll_GetSymbol(OpenGLModuleHandle,"glCopyTexImage2D"); dglCopyTexSubImage1D = (glCopyTexSubImage1D_fp)dll_GetSymbol(OpenGLModuleHandle,"glCopyTexSubImage1D"); dglCopyTexSubImage2D = (glCopyTexSubImage2D_fp)dll_GetSymbol(OpenGLModuleHandle,"glCopyTexSubImage2D"); dglCullFace = (glCullFace_fp)dll_GetSymbol(OpenGLModuleHandle,"glCullFace"); dglDeleteLists = (glDeleteLists_fp)dll_GetSymbol(OpenGLModuleHandle,"glDeleteLists"); dglDeleteTextures = (glDeleteTextures_fp)dll_GetSymbol(OpenGLModuleHandle,"glDeleteTextures"); dglDepthFunc = (glDepthFunc_fp)dll_GetSymbol(OpenGLModuleHandle,"glDepthFunc"); dglDepthMask = (glDepthMask_fp)dll_GetSymbol(OpenGLModuleHandle,"glDepthMask"); dglDepthRange = (glDepthRange_fp)dll_GetSymbol(OpenGLModuleHandle,"glDepthRange"); dglDisable = (glDisable_fp)dll_GetSymbol(OpenGLModuleHandle,"glDisable"); dglDisableClientState = (glDisableClientState_fp)dll_GetSymbol(OpenGLModuleHandle,"glDisableClientState"); dglDrawArrays = (glDrawArrays_fp)dll_GetSymbol(OpenGLModuleHandle,"glDrawArrays"); dglDrawBuffer = (glDrawBuffer_fp)dll_GetSymbol(OpenGLModuleHandle,"glDrawBuffer"); dglDrawElements = (glDrawElements_fp)dll_GetSymbol(OpenGLModuleHandle,"glDrawElements"); dglDrawPixels = (glDrawPixels_fp)dll_GetSymbol(OpenGLModuleHandle,"glDrawPixels"); dglEdgeFlag = (glEdgeFlag_fp)dll_GetSymbol(OpenGLModuleHandle,"glEdgeFlag"); dglEdgeFlagPointer = (glEdgeFlagPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glEdgeFlagPointer"); dglEdgeFlagv = (glEdgeFlagv_fp)dll_GetSymbol(OpenGLModuleHandle,"glEdgeFlagv"); dglEnable = (glEnable_fp)dll_GetSymbol(OpenGLModuleHandle,"glEnable"); dglEnableClientState = (glEnableClientState_fp)dll_GetSymbol(OpenGLModuleHandle,"glEnableClientState"); dglEnd = (glEnd_fp)dll_GetSymbol(OpenGLModuleHandle,"glEnd"); dglEndList = (glEndList_fp)dll_GetSymbol(OpenGLModuleHandle,"glEndList"); dglEvalCoord1d = (glEvalCoord1d_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord1d"); dglEvalCoord1dv = (glEvalCoord1dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord1dv"); dglEvalCoord1f = (glEvalCoord1f_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord1f"); dglEvalCoord1fv = (glEvalCoord1fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord1fv"); dglEvalCoord2d = (glEvalCoord2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord2d"); dglEvalCoord2dv = (glEvalCoord2dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord2dv"); dglEvalCoord2f = (glEvalCoord2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord2f"); dglEvalCoord2fv = (glEvalCoord2fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalCoord2fv"); dglEvalMesh1 = (glEvalMesh1_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalMesh1"); dglEvalMesh2 = (glEvalMesh2_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalMesh2"); dglEvalPoint1 = (glEvalPoint1_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalPoint1"); dglEvalPoint2 = (glEvalPoint2_fp)dll_GetSymbol(OpenGLModuleHandle,"glEvalPoint2"); dglFeedbackBuffer = (glFeedbackBuffer_fp)dll_GetSymbol(OpenGLModuleHandle,"glFeedbackBuffer"); dglFinish = (glFinish_fp)dll_GetSymbol(OpenGLModuleHandle,"glFinish"); dglFlush = (glFlush_fp)dll_GetSymbol(OpenGLModuleHandle,"glFlush"); dglFogf = (glFogf_fp)dll_GetSymbol(OpenGLModuleHandle,"glFogf"); dglFogfv = (glFogfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glFogfv"); dglFogi = (glFogi_fp)dll_GetSymbol(OpenGLModuleHandle,"glFogi"); dglFogiv = (glFogiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glFogiv"); dglFrontFace = (glFrontFace_fp)dll_GetSymbol(OpenGLModuleHandle,"glFrontFace"); dglFrustum = (glFrustum_fp)dll_GetSymbol(OpenGLModuleHandle,"glFrustum"); dglGenLists = (glGenLists_fp)dll_GetSymbol(OpenGLModuleHandle,"glGenLists"); dglGenTextures = (glGenTextures_fp)dll_GetSymbol(OpenGLModuleHandle,"glGenTextures"); dglGetBooleanv = (glGetBooleanv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetBooleanv"); dglGetClipPlane = (glGetClipPlane_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetClipPlane"); dglGetDoublev = (glGetDoublev_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetDoublev"); dglGetError = (glGetError_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetError"); dglGetFloatv = (glGetFloatv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetFloatv"); dglGetIntegerv = (glGetIntegerv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetIntegerv"); dglGetLightfv = (glGetLightfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetLightfv"); dglGetLightiv = (glGetLightiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetLightiv"); dglGetMapdv = (glGetMapdv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetMapdv"); dglGetMapfv = (glGetMapfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetMapfv"); dglGetMapiv = (glGetMapiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetMapiv"); dglGetMaterialfv = (glGetMaterialfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetMaterialfv"); dglGetMaterialiv = (glGetMaterialiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetMaterialiv"); dglGetPixelMapfv = (glGetPixelMapfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetPixelMapfv"); dglGetPixelMapuiv = (glGetPixelMapuiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetPixelMapuiv"); dglGetPixelMapusv = (glGetPixelMapusv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetPixelMapusv"); dglGetPointerv = (glGetPointerv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetPointerv"); dglGetPolygonStipple = (glGetPolygonStipple_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetPolygonStipple"); dglGetString = (glGetString_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetString"); dglGetTexEnvfv = (glGetTexEnvfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexEnvfv"); dglGetTexEnviv = (glGetTexEnviv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexEnviv"); dglGetTexGendv = (glGetTexGendv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexGendv"); dglGetTexGenfv = (glGetTexGenfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexGenfv"); dglGetTexGeniv = (glGetTexGeniv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexGeniv"); dglGetTexImage = (glGetTexImage_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexImage"); dglGetTexLevelParameterfv = (glGetTexLevelParameterfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexLevelParameterfv"); dglGetTexLevelParameteriv = (glGetTexLevelParameteriv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexLevelParameteriv"); dglGetTexParameterfv = (glGetTexParameterfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexParameterfv"); dglGetTexParameteriv = (glGetTexParameteriv_fp)dll_GetSymbol(OpenGLModuleHandle,"glGetTexParameteriv"); dglHint = (glHint_fp)dll_GetSymbol(OpenGLModuleHandle,"glHint"); dglIndexMask = (glIndexMask_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexMask"); dglIndexPointer = (glIndexPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexPointer"); dglIndexd = (glIndexd_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexd"); dglIndexdv = (glIndexdv_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexdv"); dglIndexf = (glIndexf_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexf"); dglIndexfv = (glIndexfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexfv"); dglIndexi = (glIndexi_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexi"); dglIndexiv = (glIndexiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexiv"); dglIndexs = (glIndexs_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexs"); dglIndexsv = (glIndexsv_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexsv"); dglIndexub = (glIndexub_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexub"); dglIndexubv = (glIndexubv_fp)dll_GetSymbol(OpenGLModuleHandle,"glIndexubv"); dglInitNames = (glInitNames_fp)dll_GetSymbol(OpenGLModuleHandle,"glInitNames"); dglInterleavedArrays = (glInterleavedArrays_fp)dll_GetSymbol(OpenGLModuleHandle,"glInterleavedArrays"); dglIsEnabled = (glIsEnabled_fp)dll_GetSymbol(OpenGLModuleHandle,"glIsEnabled"); dglIsList = (glIsList_fp)dll_GetSymbol(OpenGLModuleHandle,"glIsList"); dglIsTexture = (glIsTexture_fp)dll_GetSymbol(OpenGLModuleHandle,"glIsTexture"); dglLightModelf = (glLightModelf_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightModelf"); dglLightModelfv = (glLightModelfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightModelfv"); dglLightModeli = (glLightModeli_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightModeli"); dglLightModeliv = (glLightModeliv_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightModeliv"); dglLightf = (glLightf_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightf"); dglLightfv = (glLightfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightfv"); dglLighti = (glLighti_fp)dll_GetSymbol(OpenGLModuleHandle,"glLighti"); dglLightiv = (glLightiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glLightiv"); dglLineStipple = (glLineStipple_fp)dll_GetSymbol(OpenGLModuleHandle,"glLineStipple"); dglLineWidth = (glLineWidth_fp)dll_GetSymbol(OpenGLModuleHandle,"glLineWidth"); dglListBase = (glListBase_fp)dll_GetSymbol(OpenGLModuleHandle,"glListBase"); dglLoadIdentity = (glLoadIdentity_fp)dll_GetSymbol(OpenGLModuleHandle,"glLoadIdentity"); dglLoadMatrixd = (glLoadMatrixd_fp)dll_GetSymbol(OpenGLModuleHandle,"glLoadMatrixd"); dglLoadMatrixf = (glLoadMatrixf_fp)dll_GetSymbol(OpenGLModuleHandle,"glLoadMatrixf"); dglLoadName = (glLoadName_fp)dll_GetSymbol(OpenGLModuleHandle,"glLoadName"); dglLogicOp = (glLogicOp_fp)dll_GetSymbol(OpenGLModuleHandle,"glLogicOp"); dglMap1d = (glMap1d_fp)dll_GetSymbol(OpenGLModuleHandle,"glMap1d"); dglMap1f = (glMap1f_fp)dll_GetSymbol(OpenGLModuleHandle,"glMap1f"); dglMap2d = (glMap2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glMap2d"); dglMap2f = (glMap2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glMap2f"); dglMapGrid1d = (glMapGrid1d_fp)dll_GetSymbol(OpenGLModuleHandle,"glMapGrid1d"); dglMapGrid1f = (glMapGrid1f_fp)dll_GetSymbol(OpenGLModuleHandle,"glMapGrid1f"); dglMapGrid2d = (glMapGrid2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glMapGrid2d"); dglMapGrid2f = (glMapGrid2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glMapGrid2f"); dglMaterialf = (glMaterialf_fp)dll_GetSymbol(OpenGLModuleHandle,"glMaterialf"); dglMaterialfv = (glMaterialfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glMaterialfv"); dglMateriali = (glMateriali_fp)dll_GetSymbol(OpenGLModuleHandle,"glMateriali"); dglMaterialiv = (glMaterialiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glMaterialiv"); dglMatrixMode = (glMatrixMode_fp)dll_GetSymbol(OpenGLModuleHandle,"glMatrixMode"); dglMultMatrixd = (glMultMatrixd_fp)dll_GetSymbol(OpenGLModuleHandle,"glMultMatrixd"); dglMultMatrixf = (glMultMatrixf_fp)dll_GetSymbol(OpenGLModuleHandle,"glMultMatrixf"); dglNewList = (glNewList_fp)dll_GetSymbol(OpenGLModuleHandle,"glNewList"); dglNormal3b = (glNormal3b_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3b"); dglNormal3bv = (glNormal3bv_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3bv"); dglNormal3d = (glNormal3d_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3d"); dglNormal3dv = (glNormal3dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3dv"); dglNormal3f = (glNormal3f_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3f"); dglNormal3fv = (glNormal3fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3fv"); dglNormal3i = (glNormal3i_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3i"); dglNormal3iv = (glNormal3iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3iv"); dglNormal3s = (glNormal3s_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3s"); dglNormal3sv = (glNormal3sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormal3sv"); dglNormalPointer = (glNormalPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glNormalPointer"); dglOrtho = (glOrtho_fp)dll_GetSymbol(OpenGLModuleHandle,"glOrtho"); dglPassThrough = (glPassThrough_fp)dll_GetSymbol(OpenGLModuleHandle,"glPassThrough"); dglPixelMapfv = (glPixelMapfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelMapfv"); dglPixelMapuiv = (glPixelMapuiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelMapuiv"); dglPixelMapusv = (glPixelMapusv_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelMapusv"); dglPixelStoref = (glPixelStoref_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelStoref"); dglPixelStorei = (glPixelStorei_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelStorei"); dglPixelTransferf = (glPixelTransferf_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelTransferf"); dglPixelTransferi = (glPixelTransferi_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelTransferi"); dglPixelZoom = (glPixelZoom_fp)dll_GetSymbol(OpenGLModuleHandle,"glPixelZoom"); dglPointSize = (glPointSize_fp)dll_GetSymbol(OpenGLModuleHandle,"glPointSize"); dglPolygonMode = (glPolygonMode_fp)dll_GetSymbol(OpenGLModuleHandle,"glPolygonMode"); dglPolygonOffset = (glPolygonOffset_fp)dll_GetSymbol(OpenGLModuleHandle,"glPolygonOffset"); dglPolygonStipple = (glPolygonStipple_fp)dll_GetSymbol(OpenGLModuleHandle,"glPolygonStipple"); dglPopAttrib = (glPopAttrib_fp)dll_GetSymbol(OpenGLModuleHandle,"glPopAttrib"); dglPopClientAttrib = (glPopClientAttrib_fp)dll_GetSymbol(OpenGLModuleHandle,"glPopClientAttrib"); dglPopMatrix = (glPopMatrix_fp)dll_GetSymbol(OpenGLModuleHandle,"glPopMatrix"); dglPopName = (glPopName_fp)dll_GetSymbol(OpenGLModuleHandle,"glPopName"); dglPrioritizeTextures = (glPrioritizeTextures_fp)dll_GetSymbol(OpenGLModuleHandle,"glPrioritizeTextures"); dglPushAttrib = (glPushAttrib_fp)dll_GetSymbol(OpenGLModuleHandle,"glPushAttrib"); dglPushClientAttrib = (glPushClientAttrib_fp)dll_GetSymbol(OpenGLModuleHandle,"glPushClientAttrib"); dglPushMatrix = (glPushMatrix_fp)dll_GetSymbol(OpenGLModuleHandle,"glPushMatrix"); dglPushName = (glPushName_fp)dll_GetSymbol(OpenGLModuleHandle,"glPushName"); dglRasterPos2d = (glRasterPos2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2d"); dglRasterPos2dv = (glRasterPos2dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2dv"); dglRasterPos2f = (glRasterPos2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2f"); dglRasterPos2fv = (glRasterPos2fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2fv"); dglRasterPos2i = (glRasterPos2i_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2i"); dglRasterPos2iv = (glRasterPos2iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2iv"); dglRasterPos2s = (glRasterPos2s_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2s"); dglRasterPos2sv = (glRasterPos2sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos2sv"); dglRasterPos3d = (glRasterPos3d_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3d"); dglRasterPos3dv = (glRasterPos3dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3dv"); dglRasterPos3f = (glRasterPos3f_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3f"); dglRasterPos3fv = (glRasterPos3fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3fv"); dglRasterPos3i = (glRasterPos3i_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3i"); dglRasterPos3iv = (glRasterPos3iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3iv"); dglRasterPos3s = (glRasterPos3s_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3s"); dglRasterPos3sv = (glRasterPos3sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos3sv"); dglRasterPos4d = (glRasterPos4d_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4d"); dglRasterPos4dv = (glRasterPos4dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4dv"); dglRasterPos4f = (glRasterPos4f_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4f"); dglRasterPos4fv = (glRasterPos4fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4fv"); dglRasterPos4i = (glRasterPos4i_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4i"); dglRasterPos4iv = (glRasterPos4iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4iv"); dglRasterPos4s = (glRasterPos4s_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4s"); dglRasterPos4sv = (glRasterPos4sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRasterPos4sv"); dglReadBuffer = (glReadBuffer_fp)dll_GetSymbol(OpenGLModuleHandle,"glReadBuffer"); dglReadPixels = (glReadPixels_fp)dll_GetSymbol(OpenGLModuleHandle,"glReadPixels"); dglRectd = (glRectd_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectd"); dglRectdv = (glRectdv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectdv"); dglRectf = (glRectf_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectf"); dglRectfv = (glRectfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectfv"); dglRecti = (glRecti_fp)dll_GetSymbol(OpenGLModuleHandle,"glRecti"); dglRectiv = (glRectiv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectiv"); dglRects = (glRects_fp)dll_GetSymbol(OpenGLModuleHandle,"glRects"); dglRectsv = (glRectsv_fp)dll_GetSymbol(OpenGLModuleHandle,"glRectsv"); dglRenderMode = (glRenderMode_fp)dll_GetSymbol(OpenGLModuleHandle,"glRenderMode"); dglRotated = (glRotated_fp)dll_GetSymbol(OpenGLModuleHandle,"glRotated"); dglRotatef = (glRotatef_fp)dll_GetSymbol(OpenGLModuleHandle,"glRotatef"); dglScaled = (glScaled_fp)dll_GetSymbol(OpenGLModuleHandle,"glScaled"); dglScalef = (glScalef_fp)dll_GetSymbol(OpenGLModuleHandle,"glScalef"); dglScissor = (glScissor_fp)dll_GetSymbol(OpenGLModuleHandle,"glScissor"); dglSelectBuffer = (glSelectBuffer_fp)dll_GetSymbol(OpenGLModuleHandle,"glSelectBuffer"); dglShadeModel = (glShadeModel_fp)dll_GetSymbol(OpenGLModuleHandle,"glShadeModel"); dglStencilFunc = (glStencilFunc_fp)dll_GetSymbol(OpenGLModuleHandle,"glStencilFunc"); dglStencilMask = (glStencilMask_fp)dll_GetSymbol(OpenGLModuleHandle,"glStencilMask"); dglStencilOp = (glStencilOp_fp)dll_GetSymbol(OpenGLModuleHandle,"glStencilOp"); dglTexCoord1d = (glTexCoord1d_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1d"); dglTexCoord1dv = (glTexCoord1dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1dv"); dglTexCoord1f = (glTexCoord1f_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1f"); dglTexCoord1fv = (glTexCoord1fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1fv"); dglTexCoord1i = (glTexCoord1i_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1i"); dglTexCoord1iv = (glTexCoord1iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1iv"); dglTexCoord1s = (glTexCoord1s_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1s"); dglTexCoord1sv = (glTexCoord1sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord1sv"); dglTexCoord2d = (glTexCoord2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2d"); dglTexCoord2dv = (glTexCoord2dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2dv"); dglTexCoord2f = (glTexCoord2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2f"); dglTexCoord2fv = (glTexCoord2fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2fv"); dglTexCoord2i = (glTexCoord2i_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2i"); dglTexCoord2iv = (glTexCoord2iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2iv"); dglTexCoord2s = (glTexCoord2s_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2s"); dglTexCoord2sv = (glTexCoord2sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord2sv"); dglTexCoord3d = (glTexCoord3d_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3d"); dglTexCoord3dv = (glTexCoord3dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3dv"); dglTexCoord3f = (glTexCoord3f_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3f"); dglTexCoord3fv = (glTexCoord3fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3fv"); dglTexCoord3i = (glTexCoord3i_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3i"); dglTexCoord3iv = (glTexCoord3iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3iv"); dglTexCoord3s = (glTexCoord3s_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3s"); dglTexCoord3sv = (glTexCoord3sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord3sv"); dglTexCoord4d = (glTexCoord4d_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4d"); dglTexCoord4dv = (glTexCoord4dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4dv"); dglTexCoord4f = (glTexCoord4f_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4f"); dglTexCoord4fv = (glTexCoord4fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4fv"); dglTexCoord4i = (glTexCoord4i_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4i"); dglTexCoord4iv = (glTexCoord4iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4iv"); dglTexCoord4s = (glTexCoord4s_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4s"); dglTexCoord4sv = (glTexCoord4sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoord4sv"); dglTexCoordPointer = (glTexCoordPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexCoordPointer"); dglTexEnvf = (glTexEnvf_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexEnvf"); dglTexEnvfv = (glTexEnvfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexEnvfv"); dglTexEnvi = (glTexEnvi_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexEnvi"); dglTexEnviv = (glTexEnviv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexEnviv"); dglTexGend = (glTexGend_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGend"); dglTexGendv = (glTexGendv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGendv"); dglTexGenf = (glTexGenf_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGenf"); dglTexGenfv = (glTexGenfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGenfv"); dglTexGeni = (glTexGeni_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGeni"); dglTexGeniv = (glTexGeniv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexGeniv"); dglTexImage1D = (glTexImage1D_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexImage1D"); dglTexImage2D = (glTexImage2D_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexImage2D"); dglTexParameterf = (glTexParameterf_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexParameterf"); dglTexParameterfv = (glTexParameterfv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexParameterfv"); dglTexParameteri = (glTexParameteri_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexParameteri"); dglTexParameteriv = (glTexParameteriv_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexParameteriv"); dglTexSubImage1D = (glTexSubImage1D_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexSubImage1D"); dglTexSubImage2D = (glTexSubImage2D_fp)dll_GetSymbol(OpenGLModuleHandle,"glTexSubImage2D"); dglTranslated = (glTranslated_fp)dll_GetSymbol(OpenGLModuleHandle,"glTranslated"); dglTranslatef = (glTranslatef_fp)dll_GetSymbol(OpenGLModuleHandle,"glTranslatef"); dglVertex2d = (glVertex2d_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2d"); dglVertex2dv = (glVertex2dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2dv"); dglVertex2f = (glVertex2f_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2f"); dglVertex2fv = (glVertex2fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2fv"); dglVertex2i = (glVertex2i_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2i"); dglVertex2iv = (glVertex2iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2iv"); dglVertex2s = (glVertex2s_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2s"); dglVertex2sv = (glVertex2sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex2sv"); dglVertex3d = (glVertex3d_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3d"); dglVertex3dv = (glVertex3dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3dv"); dglVertex3f = (glVertex3f_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3f"); dglVertex3fv = (glVertex3fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3fv"); dglVertex3i = (glVertex3i_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3i"); dglVertex3iv = (glVertex3iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3iv"); dglVertex3s = (glVertex3s_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3s"); dglVertex3sv = (glVertex3sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex3sv"); dglVertex4d = (glVertex4d_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4d"); dglVertex4dv = (glVertex4dv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4dv"); dglVertex4f = (glVertex4f_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4f"); dglVertex4fv = (glVertex4fv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4fv"); dglVertex4i = (glVertex4i_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4i"); dglVertex4iv = (glVertex4iv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4iv"); dglVertex4s = (glVertex4s_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4s"); dglVertex4sv = (glVertex4sv_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertex4sv"); dglVertexPointer = (glVertexPointer_fp)dll_GetSymbol(OpenGLModuleHandle,"glVertexPointer"); dglViewport = (glViewport_fp)dll_GetSymbol(OpenGLModuleHandle,"glViewport"); #ifdef _WIN32 dwglCopyContext = (wglCopyContext_fp)dll_GetSymbol(OpenGLModuleHandle,"wglCopyContext"); dwglCreateContext = (wglCreateContext_fp)dll_GetSymbol(OpenGLModuleHandle,"wglCreateContext"); dwglCreateLayerContext = (wglCreateLayerContext_fp)dll_GetSymbol(OpenGLModuleHandle,"wglCreateLayerContext"); dwglDeleteContext = (wglDeleteContext_fp)dll_GetSymbol(OpenGLModuleHandle,"wglDeleteContext"); dwglGetCurrentContext = (wglGetCurrentContext_fp)dll_GetSymbol(OpenGLModuleHandle,"wglGetCurrentContext"); dwglGetCurrentDC = (wglGetCurrentDC_fp)dll_GetSymbol(OpenGLModuleHandle,"wglGetCurrentDC"); dwglGetProcAddress = (wglGetProcAddress_fp)dll_GetSymbol(OpenGLModuleHandle,"wglGetProcAddress"); dwglMakeCurrent = (wglMakeCurrent_fp)dll_GetSymbol(OpenGLModuleHandle,"wglMakeCurrent"); dwglShareLists = (wglShareLists_fp)dll_GetSymbol(OpenGLModuleHandle,"wglShareLists"); dwglUseFontBitmapsA = (wglUseFontBitmapsA_fp)dll_GetSymbol(OpenGLModuleHandle,"wglUseFontBitmapsA"); dwglUseFontBitmapsW = (wglUseFontBitmapsW_fp)dll_GetSymbol(OpenGLModuleHandle,"wglUseFontBitmapsW"); dwglUseFontOutlinesA = (wglUseFontOutlinesA_fp)dll_GetSymbol(OpenGLModuleHandle,"wglUseFontOutlinesA"); dwglUseFontOutlinesW = (wglUseFontOutlinesW_fp)dll_GetSymbol(OpenGLModuleHandle,"wglUseFontOutlinesW"); dwglDescribeLayerPlane = (wglDescribeLayerPlane_fp)dll_GetSymbol(OpenGLModuleHandle,"wglDescribeLayerPlane"); dwglSetLayerPaletteEntries = (wglSetLayerPaletteEntries_fp)dll_GetSymbol(OpenGLModuleHandle,"wglSetLayerPaletteEntries"); dwglGetLayerPaletteEntries = (wglGetLayerPaletteEntries_fp)dll_GetSymbol(OpenGLModuleHandle,"wglGetLayerPaletteEntries"); dwglRealizeLayerPalette = (wglRealizeLayerPalette_fp)dll_GetSymbol(OpenGLModuleHandle,"wglRealizeLayerPalette"); dwglSwapLayerBuffers = (wglSwapLayerBuffers_fp)dll_GetSymbol(OpenGLModuleHandle,"wglSwapLayerBuffers"); #if (WINVER >= 0x0500) dwglSwapMultipleBuffers = (wglSwapMultipleBuffers_fp)dll_GetSymbol(OpenGLModuleHandle,"wglSwapMultipleBuffers"); #endif #endif } return true; } void OpenGL_SetFuncsToNull(void) { dglAccum = NULL; dglAlphaFunc = NULL; dglAreTexturesResident = NULL; dglArrayElement = NULL; dglBegin = NULL; dglBindTexture = NULL; dglBitmap = NULL; dglBlendFunc = NULL; dglCallList = NULL; dglCallLists = NULL; dglClear = NULL; dglClearAccum = NULL; dglClearColor = NULL; dglClearDepth = NULL; dglClearIndex = NULL; dglClearStencil = NULL; dglClipPlane = NULL; dglColor3b = NULL; dglColor3bv = NULL; dglColor3d = NULL; dglColor3dv = NULL; dglColor3f = NULL; dglColor3fv = NULL; dglColor3i = NULL; dglColor3iv = NULL; dglColor3s = NULL; dglColor3sv = NULL; dglColor3ub = NULL; dglColor3ubv = NULL; dglColor3ui = NULL; dglColor3uiv = NULL; dglColor3us = NULL; dglColor3usv = NULL; dglColor4b = NULL; dglColor4bv = NULL; dglColor4d = NULL; dglColor4dv = NULL; dglColor4f = NULL; dglColor4fv = NULL; dglColor4i = NULL; dglColor4iv = NULL; dglColor4s = NULL; dglColor4sv = NULL; dglColor4ub = NULL; dglColor4ubv = NULL; dglColor4ui = NULL; dglColor4uiv = NULL; dglColor4us = NULL; dglColor4usv = NULL; dglColorMask = NULL; dglColorMaterial = NULL; dglColorPointer = NULL; dglCopyPixels = NULL; dglCopyTexImage1D = NULL; dglCopyTexImage2D = NULL; dglCopyTexSubImage1D = NULL; dglCopyTexSubImage2D = NULL; dglCullFace = NULL; dglDeleteLists = NULL; dglDeleteTextures = NULL; dglDepthFunc = NULL; dglDepthMask = NULL; dglDepthRange = NULL; dglDisable = NULL; dglDisableClientState = NULL; dglDrawArrays = NULL; dglDrawBuffer = NULL; dglDrawElements = NULL; dglDrawPixels = NULL; dglEdgeFlag = NULL; dglEdgeFlagPointer = NULL; dglEdgeFlagv = NULL; dglEnable = NULL; dglEnableClientState = NULL; dglEnd = NULL; dglEndList = NULL; dglEvalCoord1d = NULL; dglEvalCoord1dv = NULL; dglEvalCoord1f = NULL; dglEvalCoord1fv = NULL; dglEvalCoord2d = NULL; dglEvalCoord2dv = NULL; dglEvalCoord2f = NULL; dglEvalCoord2fv = NULL; dglEvalMesh1 = NULL; dglEvalMesh2 = NULL; dglEvalPoint1 = NULL; dglEvalPoint2 = NULL; dglFeedbackBuffer = NULL; dglFinish = NULL; dglFlush = NULL; dglFogf = NULL; dglFogfv = NULL; dglFogi = NULL; dglFogiv = NULL; dglFrontFace = NULL; dglFrustum = NULL; dglGenLists = NULL; dglGenTextures = NULL; dglGetBooleanv = NULL; dglGetClipPlane = NULL; dglGetDoublev = NULL; dglGetError = NULL; dglGetFloatv = NULL; dglGetIntegerv = NULL; dglGetLightfv = NULL; dglGetLightiv = NULL; dglGetMapdv = NULL; dglGetMapfv = NULL; dglGetMapiv = NULL; dglGetMaterialfv = NULL; dglGetMaterialiv = NULL; dglGetPixelMapfv = NULL; dglGetPixelMapuiv = NULL; dglGetPixelMapusv = NULL; dglGetPointerv = NULL; dglGetPolygonStipple = NULL; dglGetString = NULL; dglGetTexEnvfv = NULL; dglGetTexEnviv = NULL; dglGetTexGendv = NULL; dglGetTexGenfv = NULL; dglGetTexGeniv = NULL; dglGetTexImage = NULL; dglGetTexLevelParameterfv = NULL; dglGetTexLevelParameteriv = NULL; dglGetTexParameterfv = NULL; dglGetTexParameteriv = NULL; dglHint = NULL; dglIndexMask = NULL; dglIndexPointer = NULL; dglIndexd = NULL; dglIndexdv = NULL; dglIndexf = NULL; dglIndexfv = NULL; dglIndexi = NULL; dglIndexiv = NULL; dglIndexs = NULL; dglIndexsv = NULL; dglIndexub = NULL; dglIndexubv = NULL; dglInitNames = NULL; dglInterleavedArrays = NULL; dglIsEnabled = NULL; dglIsList = NULL; dglIsTexture = NULL; dglLightModelf = NULL; dglLightModelfv = NULL; dglLightModeli = NULL; dglLightModeliv = NULL; dglLightf = NULL; dglLightfv = NULL; dglLighti = NULL; dglLightiv = NULL; dglLineStipple = NULL; dglLineWidth = NULL; dglListBase = NULL; dglLoadIdentity = NULL; dglLoadMatrixd = NULL; dglLoadMatrixf = NULL; dglLoadName = NULL; dglLogicOp = NULL; dglMap1d = NULL; dglMap1f = NULL; dglMap2d = NULL; dglMap2f = NULL; dglMapGrid1d = NULL; dglMapGrid1f = NULL; dglMapGrid2d = NULL; dglMapGrid2f = NULL; dglMaterialf = NULL; dglMaterialfv = NULL; dglMateriali = NULL; dglMaterialiv = NULL; dglMatrixMode = NULL; dglMultMatrixd = NULL; dglMultMatrixf = NULL; dglNewList = NULL; dglNormal3b = NULL; dglNormal3bv = NULL; dglNormal3d = NULL; dglNormal3dv = NULL; dglNormal3f = NULL; dglNormal3fv = NULL; dglNormal3i = NULL; dglNormal3iv = NULL; dglNormal3s = NULL; dglNormal3sv = NULL; dglNormalPointer = NULL; dglOrtho = NULL; dglPassThrough = NULL; dglPixelMapfv = NULL; dglPixelMapuiv = NULL; dglPixelMapusv = NULL; dglPixelStoref = NULL; dglPixelStorei = NULL; dglPixelTransferf = NULL; dglPixelTransferi = NULL; dglPixelZoom = NULL; dglPointSize = NULL; dglPolygonMode = NULL; dglPolygonOffset = NULL; dglPolygonStipple = NULL; dglPopAttrib = NULL; dglPopClientAttrib = NULL; dglPopMatrix = NULL; dglPopName = NULL; dglPrioritizeTextures = NULL; dglPushAttrib = NULL; dglPushClientAttrib = NULL; dglPushMatrix = NULL; dglPushName = NULL; dglRasterPos2d = NULL; dglRasterPos2dv = NULL; dglRasterPos2f = NULL; dglRasterPos2fv = NULL; dglRasterPos2i = NULL; dglRasterPos2iv = NULL; dglRasterPos2s = NULL; dglRasterPos2sv = NULL; dglRasterPos3d = NULL; dglRasterPos3dv = NULL; dglRasterPos3f = NULL; dglRasterPos3fv = NULL; dglRasterPos3i = NULL; dglRasterPos3iv = NULL; dglRasterPos3s = NULL; dglRasterPos3sv = NULL; dglRasterPos4d = NULL; dglRasterPos4dv = NULL; dglRasterPos4f = NULL; dglRasterPos4fv = NULL; dglRasterPos4i = NULL; dglRasterPos4iv = NULL; dglRasterPos4s = NULL; dglRasterPos4sv = NULL; dglReadBuffer = NULL; dglReadPixels = NULL; dglRectd = NULL; dglRectdv = NULL; dglRectf = NULL; dglRectfv = NULL; dglRecti = NULL; dglRectiv = NULL; dglRects = NULL; dglRectsv = NULL; dglRenderMode = NULL; dglRotated = NULL; dglRotatef = NULL; dglScaled = NULL; dglScalef = NULL; dglScissor = NULL; dglSelectBuffer = NULL; dglShadeModel = NULL; dglStencilFunc = NULL; dglStencilMask = NULL; dglStencilOp = NULL; dglTexCoord1d = NULL; dglTexCoord1dv = NULL; dglTexCoord1f = NULL; dglTexCoord1fv = NULL; dglTexCoord1i = NULL; dglTexCoord1iv = NULL; dglTexCoord1s = NULL; dglTexCoord1sv = NULL; dglTexCoord2d = NULL; dglTexCoord2dv = NULL; dglTexCoord2f = NULL; dglTexCoord2fv = NULL; dglTexCoord2i = NULL; dglTexCoord2iv = NULL; dglTexCoord2s = NULL; dglTexCoord2sv = NULL; dglTexCoord3d = NULL; dglTexCoord3dv = NULL; dglTexCoord3f = NULL; dglTexCoord3fv = NULL; dglTexCoord3i = NULL; dglTexCoord3iv = NULL; dglTexCoord3s = NULL; dglTexCoord3sv = NULL; dglTexCoord4d = NULL; dglTexCoord4dv = NULL; dglTexCoord4f = NULL; dglTexCoord4fv = NULL; dglTexCoord4i = NULL; dglTexCoord4iv = NULL; dglTexCoord4s = NULL; dglTexCoord4sv = NULL; dglTexCoordPointer = NULL; dglTexEnvf = NULL; dglTexEnvfv = NULL; dglTexEnvi = NULL; dglTexEnviv = NULL; dglTexGend = NULL; dglTexGendv = NULL; dglTexGenf = NULL; dglTexGenfv = NULL; dglTexGeni = NULL; dglTexGeniv = NULL; dglTexImage1D = NULL; dglTexImage2D = NULL; dglTexParameterf = NULL; dglTexParameterfv = NULL; dglTexParameteri = NULL; dglTexParameteriv = NULL; dglTexSubImage1D = NULL; dglTexSubImage2D = NULL; dglTranslated = NULL; dglTranslatef = NULL; dglVertex2d = NULL; dglVertex2dv = NULL; dglVertex2f = NULL; dglVertex2fv = NULL; dglVertex2i = NULL; dglVertex2iv = NULL; dglVertex2s = NULL; dglVertex2sv = NULL; dglVertex3d = NULL; dglVertex3dv = NULL; dglVertex3f = NULL; dglVertex3fv = NULL; dglVertex3i = NULL; dglVertex3iv = NULL; dglVertex3s = NULL; dglVertex3sv = NULL; dglVertex4d = NULL; dglVertex4dv = NULL; dglVertex4f = NULL; dglVertex4fv = NULL; dglVertex4i = NULL; dglVertex4iv = NULL; dglVertex4s = NULL; dglVertex4sv = NULL; dglVertexPointer = NULL; dglViewport = NULL; dglMultiTexCoord2fARB = NULL; dglActiveTextureARB = NULL; dglMultiTexCoord2fSGIS = NULL; dglSelectTextureSGIS = NULL; #ifdef _WIN32 dwglCopyContext = NULL; dwglCreateContext = NULL; dwglCreateLayerContext = NULL; dwglDeleteContext = NULL; dwglGetCurrentContext = NULL; dwglGetCurrentDC = NULL; dwglGetProcAddress = NULL; dwglMakeCurrent = NULL; dwglShareLists = NULL; dwglUseFontBitmapsA = NULL; dwglUseFontBitmapsW = NULL; dwglUseFontOutlinesA = NULL; dwglUseFontOutlinesW = NULL; dwglDescribeLayerPlane = NULL; dwglSetLayerPaletteEntries = NULL; dwglGetLayerPaletteEntries = NULL; dwglRealizeLayerPalette = NULL; dwglSwapLayerBuffers = NULL; #if (WINVER >= 0x0500) dwglSwapMultipleBuffers = NULL; #endif #endif } #endif #endif //!__LOADGL_H__ dxx-rebirth-0.58.1-d1x/include/makesig.h000066400000000000000000000007601217717257200177710ustar00rootroot00000000000000/* * $Source: /cvsroot/dxx-rebirth/d2x-rebirth/include/makesig.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 20:01:26 $ * * Macro to make file signatures * * $Log: makesig.h,v $ * Revision 1.1.1.1 2006/03/17 20:01:26 zicodxx * initial import * * Revision 1.1 2001/11/11 23:39:22 bradleyb * Created header for MAKE_SIG macro * * */ #ifndef _MAKESIG_H #define _MAKESIG_H #define MAKE_SIG(a,b,c,d) (((long)(a)<<24)+((long)(b)<<16)+((c)<<8)+(d)) #endif dxx-rebirth-0.58.1-d1x/include/maths.h000066400000000000000000000057631217717257200174750ustar00rootroot00000000000000/* Maths.h library header file */ #ifndef _MATHS_H #define _MATHS_H #include #include "pstypes.h" #define D_RAND_MAX 32767 void d_srand (unsigned int seed); int d_rand (); // Random number function which returns in the range 0-0x7FFF //=============================== FIXED POINT =============================== typedef int64_t fix64; //64 bits int, for timers typedef int32_t fix; //16 bits int, 16 bits frac typedef int16_t fixang; //angles typedef struct quadint // integer 64 bit, previously called "quad" { u_int32_t low; int32_t high; } quadint; //Convert an int to a fix/fix64 and back #define i2f(i) ((i)<<16) #define f2i(f) ((f)>>16) //Get the int part of a fix, with rounding #define f2ir(f) (((f)+f0_5)>>16) //Convert fix to float and float to fix #define f2fl(f) (((float) (f)) / 65536.0) #define f2db(f) (((double) (f)) / 65536.0) #define fl2f(f) ((fix) ((f) * 65536)) //Some handy constants #define f0_0 0 #define f1_0 0x10000 #define f2_0 0x20000 #define f3_0 0x30000 #define f10_0 0xa0000 #define f0_5 0x8000 #define f0_1 0x199a #define F0_0 f0_0 #define F1_0 f1_0 #define F2_0 f2_0 #define F3_0 f3_0 #define F10_0 f10_0 #define F0_5 f0_5 #define F0_1 f0_1 //multiply two fixes, return a fix(64) fix fixmul (fix a, fix b); fix64 fixmul64 (fix a, fix b); //divide two fixes, return a fix fix fixdiv (fix a, fix b); //multiply two fixes, then divide by a third, return a fix fix fixmuldiv (fix a, fix b, fix c); //multiply two fixes, and add 64-bit product to a quadint void fixmulaccum (quadint * q, fix a, fix b); //extract a fix from a quadint product fix fixquadadjust (quadint * q); //divide a quadint by a long int32_t fixdivquadlong (u_int32_t qlow, u_int32_t qhigh, u_int32_t d); //negate a quadint void fixquadnegate (quadint * q); //computes the square root of a long, returning a short ushort long_sqrt (int32_t a); //computes the square root of a quadint, returning a long u_int32_t quad_sqrt (u_int32_t low, int32_t high); //unsigned long quad_sqrt (long low, long high); //computes the square root of a fix, returning a fix fix fix_sqrt (fix a); //compute sine and cosine of an angle, filling in the variables //either of the pointers can be NULL void fix_sincos (fix a, fix * s, fix * c); //with interpolation void fix_fastsincos (fix a, fix * s, fix * c); //no interpolation //compute inverse sine & cosine fixang fix_asin (fix v); fixang fix_acos (fix v); //given cos & sin of an angle, return that angle. //parms need not be normalized, that is, the ratio of the parms cos/sin must //equal the ratio of the actual cos & sin for the result angle, but the parms //need not be the actual cos & sin. //NOTE: this is different from the standard C atan2, since it is left-handed. fixang fix_atan2 (fix cos, fix sin); //for passed value a, returns 1/sqrt(a) fix fix_isqrt (fix a); extern const ubyte guess_table[]; extern const short sincos_table[]; extern const ushort asin_table[]; extern const ushort acos_table[]; extern const fix isqrt_guess_table[]; #endif dxx-rebirth-0.58.1-d1x/include/ogl_init.h000066400000000000000000000060661217717257200201620ustar00rootroot00000000000000/* interface to OpenGL functions * Added 9/15/99 Matthew Mueller * Got rid of OpenGL-internal stuff 2004-5-16 Martin Schaffner */ #ifndef _OGL_INIT_H_ #define _OGL_INIT_H_ #ifdef _MSC_VER #include #include #endif #ifdef _WIN32 #include "loadgl.h" int ogl_init_load_library(void); #else # define GL_GLEXT_LEGACY # if defined(__APPLE__) && defined(__MACH__) # include # include # else # define GL_GLEXT_PROTOTYPES # ifdef OGLES # include # else # include # endif # endif # ifndef GL_CLAMP_TO_EDGE // hack for Mac OS 9, others? # define GL_CLAMP_TO_EDGE GL_CLAMP # endif #endif #include "gr.h" #include "palette.h" #include "pstypes.h" #ifndef GL_VERSION_1_1 #ifdef GL_EXT_texture #define GL_INTENSITY4 GL_INTENSITY4_EXT #define GL_INTENSITY8 GL_INTENSITY8_EXT #endif #endif #ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #endif #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif /* we need to export ogl_texture for 2d/font.c */ typedef struct _ogl_texture { GLuint handle; GLint internalformat; GLenum format; int w,h,tw,th,lw; int bytesu; int bytes; GLfloat u,v; GLfloat prio; int wrapstate; unsigned long numrend; } ogl_texture; extern ogl_texture* ogl_get_free_texture(); void ogl_init_texture(ogl_texture* t, int w, int h, int flags); extern int ogl_rgba_internalformat; extern int ogl_rgb_internalformat; void ogl_init_shared_palette(void); extern int gl_initialized; extern int active_texture_unit; extern GLfloat ogl_maxanisotropy; void ogl_setActiveTexture(int t); int ogl_init_window(int x, int y);//create a window/switch modes/etc #define OGL_FLAG_MIPMAP (1 << 0) #define OGL_FLAG_NOCOLOR (1 << 1) #define OGL_FLAG_ALPHA (1 << 31) // not required for ogl_loadbmtexture, since it uses the BM_FLAG_TRANSPARENT, but is needed for ogl_init_texture. void ogl_loadbmtexture_f(grs_bitmap *bm, int texfilt); void ogl_freebmtexture(grs_bitmap *bm); void ogl_start_frame(void); void ogl_end_frame(void); void ogl_swap_buffers_internal(void); void ogl_set_screen_mode(void); void ogl_cache_level_textures(void); void ogl_urect(int left, int top, int right, int bot); bool ogl_ubitmapm_cs(int x, int y,int dw, int dh, grs_bitmap *bm,int c, int scale); bool ogl_ubitblt_i(int dw, int dh, int dx, int dy, int sw, int sh, int sx, int sy, grs_bitmap * src, grs_bitmap * dest, int texfilt); bool ogl_ubitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest); void ogl_upixelc(int x, int y, int c); unsigned char ogl_ugpixel( grs_bitmap * bitmap, int x, int y ); void ogl_ulinec(int left, int top, int right, int bot, int c); #include "3d.h" bool g3_draw_tmap_2(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb, grs_bitmap *bmbot,grs_bitmap *bm, int orient); void ogl_draw_vertex_reticle(int cross,int primary,int secondary,int color,int alpha,int size_offs); void ogl_toggle_depth_test(int enable); void ogl_set_blending(); int pow2ize(int x);//from ogl.c #endif /* _OGL_INIT_H_ */ dxx-rebirth-0.58.1-d1x/include/palette.h000066400000000000000000000023411217717257200200040ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Protoypes for palette functions * */ #ifndef _PALETTE_H #define _PALETTE_H extern void gr_palette_set_gamma( int gamma ); extern int gr_palette_get_gamma(); extern void gr_palette_load( ubyte * pal ); extern void gr_make_cthru_table(ubyte * table, ubyte r, ubyte g, ubyte b ); extern int gr_find_closest_color_current( int r, int g, int b ); extern void gr_palette_read(ubyte * palette); extern void init_computed_colors(void); extern ubyte gr_palette_gamma; extern ubyte gr_current_pal[256*3]; #endif dxx-rebirth-0.58.1-d1x/include/pcx.h000066400000000000000000000050621217717257200171430ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/pcx.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:22 $ * * Routines to read/write pcx images. * * $Log: pcx.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:22 zicodxx * initial import * * Revision 1.2 1999/11/20 10:05:16 donut * variable size menu patch from Jan Bobrowski. Variable menu font size support and a bunch of fixes for menus that didn't work quite right, by me (MPM). * * Revision 1.1.1.1 1999/06/14 22:02:19 donut * Import of d1x 1.37 source. * * Revision 1.4 1995/01/21 17:07:34 john * Added out of memory error. * * Revision 1.3 1994/11/29 02:53:10 john * Added error messages; made call be more similiar to iff. * * Revision 1.2 1994/11/28 20:03:48 john * Added PCX functions. * * Revision 1.1 1994/11/28 19:57:45 john * Initial revision * * */ #ifndef _PCX_H #define _PCX_H #define PCX_ERROR_NONE 0 #define PCX_ERROR_OPENING 1 #define PCX_ERROR_NO_HEADER 2 #define PCX_ERROR_WRONG_VERSION 3 #define PCX_ERROR_READING 4 #define PCX_ERROR_NO_PALETTE 5 #define PCX_ERROR_WRITING 6 #define PCX_ERROR_MEMORY 7 // Load bitmap for little-known 'baldguy' cheat. extern int bald_guy_load( char * filename, grs_bitmap * bmp,int bitmap_type ,ubyte * palette ); // Reads filename into bitmap bmp, and fills in palette. If bmp->bm_data==NULL, // then bmp->bm_data is allocated and the w,h are filled. // If palette==NULL the palette isn't read in. Returns error code. extern int pcx_read_bitmap( char * filename, grs_bitmap * bmp, int bitmap_type, ubyte * palette ); // Writes the bitmap bmp to filename, using palette. Returns error code. extern int pcx_write_bitmap( char * filename, grs_bitmap * bmp, ubyte * palette ); extern const char *pcx_errormsg(int error_number); #endif dxx-rebirth-0.58.1-d1x/include/physfsx.h000066400000000000000000000162611217717257200200600ustar00rootroot00000000000000 /* * * Some simple physfs extensions * */ #ifndef PHYSFSX_H #define PHYSFSX_H #include #include // When PhysicsFS can *easily* be built as a framework on Mac OS X, // the framework form will be supported again -kreatordxx #if 1 //!(defined(__APPLE__) && defined(__MACH__)) #include #else #include #endif #include "pstypes.h" #include "strutil.h" #include "u_mem.h" #include "dxxerror.h" #include "vecmat.h" #include "ignorecase.h" #include "byteswap.h" extern void PHYSFSX_init(int argc, char *argv[]); static inline int PHYSFSX_readSXE16(PHYSFS_file *file, int swap) { PHYSFS_sint16 val; PHYSFS_read(file, &val, sizeof(val), 1); return swap ? SWAPSHORT(val) : val; } static inline int PHYSFSX_readSXE32(PHYSFS_file *file, int swap) { PHYSFS_sint32 val; PHYSFS_read(file, &val, sizeof(val), 1); return swap ? SWAPINT(val) : val; } static inline void PHYSFSX_readVectorX(PHYSFS_file *file, vms_vector *v, int swap) { v->x = PHYSFSX_readSXE32(file, swap); v->y = PHYSFSX_readSXE32(file, swap); v->z = PHYSFSX_readSXE32(file, swap); } static inline void PHYSFSX_readAngleVecX(PHYSFS_file *file, vms_angvec *v, int swap) { v->p = PHYSFSX_readSXE16(file, swap); v->b = PHYSFSX_readSXE16(file, swap); v->h = PHYSFSX_readSXE16(file, swap); } static inline int PHYSFSX_readString(PHYSFS_file *file, char *s) { char *ptr = s; if (PHYSFS_eof(file)) *ptr = 0; else do PHYSFS_read(file, ptr, 1, 1); while (!PHYSFS_eof(file) && *ptr++ != 0); return strlen(s); } static inline int PHYSFSX_gets(PHYSFS_file *file, char *s) { char *ptr = s; if (PHYSFS_eof(file)) *ptr = 0; else do PHYSFS_read(file, ptr, 1, 1); while (!PHYSFS_eof(file) && *ptr++ != '\n'); return strlen(s); } static inline int PHYSFSX_writeU8(PHYSFS_file *file, PHYSFS_uint8 val) { return PHYSFS_write(file, &val, 1, 1); } static inline int PHYSFSX_writeString(PHYSFS_file *file, const char *s) { return PHYSFS_write(file, s, 1, strlen(s) + 1); } static inline int PHYSFSX_puts(PHYSFS_file *file, const char *s) { return PHYSFS_write(file, s, 1, strlen(s)); } static inline int PHYSFSX_putc(PHYSFS_file *file, int c) { unsigned char ch = (unsigned char)c; if (PHYSFS_write(file, &ch, 1, 1) < 1) return -1; else return (int)c; } static inline int PHYSFSX_fgetc(PHYSFS_file *const fp) { unsigned char c; if (PHYSFS_read(fp, &c, 1, 1) != 1) return EOF; return c; } static inline int PHYSFSX_fseek(PHYSFS_file *fp, long int offset, int where) { int c, goal_position; switch(where) { case SEEK_SET: goal_position = offset; break; case SEEK_CUR: goal_position = PHYSFS_tell(fp) + offset; break; case SEEK_END: goal_position = PHYSFS_fileLength(fp) + offset; break; default: return 1; } c = PHYSFS_seek(fp, goal_position); return !c; } static inline char * PHYSFSX_fgets(char *buf, size_t n, PHYSFS_file *const fp) { size_t i; int c; for (i = 0; i < n - 1; i++) { do { c = PHYSFSX_fgetc(fp); if (c == EOF) { *buf = 0; return NULL; } if (c == 0 || c == 10) // Unix line ending break; if (c == 13) // Mac or DOS line ending { int c1; c1 = PHYSFSX_fgetc(fp); if (c1 != EOF) // The file could end with a Mac line ending PHYSFSX_fseek(fp, -1, SEEK_CUR); if (c1 == 10) // DOS line ending continue; else // Mac line ending break; } } while (c == 13); if (c == 13) // because cr-lf is a bad thing on the mac c = '\n'; // and anyway -- 0xod is CR on mac, not 0x0a if (c == '\n') break; *buf++ = c; } *buf = 0; return buf; } static inline int PHYSFSX_printf(PHYSFS_file *file, const char *format, ...) { char buffer[1024]; va_list args; va_start(args, format); vsprintf(buffer, format, args); return PHYSFSX_puts(file, buffer); } #define PHYSFSX_writeFix PHYSFS_writeSLE32 #define PHYSFSX_writeFixAng PHYSFS_writeSLE16 static inline int PHYSFSX_writeVector(PHYSFS_file *file, vms_vector *v) { if (PHYSFSX_writeFix(file, v->x) < 1 || PHYSFSX_writeFix(file, v->y) < 1 || PHYSFSX_writeFix(file, v->z) < 1) return 0; return 1; } static inline int PHYSFSX_writeAngleVec(PHYSFS_file *file, vms_angvec *v) { if (PHYSFSX_writeFixAng(file, v->p) < 1 || PHYSFSX_writeFixAng(file, v->b) < 1 || PHYSFSX_writeFixAng(file, v->h) < 1) return 0; return 1; } static inline int PHYSFSX_writeMatrix(PHYSFS_file *file, vms_matrix *m) { if (PHYSFSX_writeVector(file, &m->rvec) < 1 || PHYSFSX_writeVector(file, &m->uvec) < 1 || PHYSFSX_writeVector(file, &m->fvec) < 1) return 0; return 1; } static inline int PHYSFSX_readInt(PHYSFS_file *file) { int i; if (!PHYSFS_readSLE32(file, &i)) { Error("Error reading int in PHYSFSX_readInt()"); exit(1); } return i; } static inline short PHYSFSX_readShort(PHYSFS_file *file) { int16_t s; if (!PHYSFS_readSLE16(file, &s)) { Error("Error reading short in PHYSFSX_readShort()"); exit(1); } return s; } static inline sbyte PHYSFSX_readByte(PHYSFS_file *file) { sbyte b; if (PHYSFS_read(file, &b, sizeof(b), 1) != 1) { Error("Error reading byte in PHYSFSX_readByte()"); exit(1); } return b; } static inline fix PHYSFSX_readFix(PHYSFS_file *file) { int f; // a fix is defined as a long for Mac OS 9, and MPW can't convert from (long *) to (int *) if (!PHYSFS_readSLE32(file, &f)) { Error("Error reading fix in PHYSFSX_readFix()"); exit(1); } return f; } static inline fixang PHYSFSX_readFixAng(PHYSFS_file *file) { fixang f; if (!PHYSFS_readSLE16(file, &f)) { Error("Error reading fixang in PHYSFSX_readFixAng()"); exit(1); } return f; } static inline void PHYSFSX_readVector(vms_vector *v, PHYSFS_file *file) { v->x = PHYSFSX_readFix(file); v->y = PHYSFSX_readFix(file); v->z = PHYSFSX_readFix(file); } static inline void PHYSFSX_readAngleVec(vms_angvec *v, PHYSFS_file *file) { v->p = PHYSFSX_readFixAng(file); v->b = PHYSFSX_readFixAng(file); v->h = PHYSFSX_readFixAng(file); } static inline void PHYSFSX_readMatrix(vms_matrix *m,PHYSFS_file *file) { PHYSFSX_readVector(&m->rvec,file); PHYSFSX_readVector(&m->uvec,file); PHYSFSX_readVector(&m->fvec,file); } #define PHYSFSX_contfile_init PHYSFSX_addRelToSearchPath #define PHYSFSX_contfile_close PHYSFSX_removeRelFromSearchPath extern int PHYSFSX_addRelToSearchPath(const char *relname, int add_to_end); extern int PHYSFSX_removeRelFromSearchPath(const char *relname); extern int PHYSFSX_fsize(const char *hogname); extern void PHYSFSX_listSearchPathContent(); extern int PHYSFSX_checkSupportedArchiveTypes(); extern int PHYSFSX_getRealPath(const char *stdPath, char *realPath); extern int PHYSFSX_isNewPath(const char *path); extern int PHYSFSX_rename(const char *oldpath, const char *newpath); extern char **PHYSFSX_findFiles(const char *path, const char *const *exts); extern char **PHYSFSX_findabsoluteFiles(const char *path, const char *realpath, const char *const *exts); extern PHYSFS_sint64 PHYSFSX_getFreeDiskSpace(); extern int PHYSFSX_exists(const char *filename, int ignorecase); extern PHYSFS_file *PHYSFSX_openReadBuffered(const char *filename); extern PHYSFS_file *PHYSFSX_openWriteBuffered(const char *filename); extern void PHYSFSX_addArchiveContent(); extern void PHYSFSX_removeArchiveContent(); #endif /* PHYSFSX_H */ dxx-rebirth-0.58.1-d1x/include/pstypes.h000066400000000000000000000042221217717257200200550ustar00rootroot00000000000000/* * * Common types and defines * */ #ifndef _TYPES_H #define _TYPES_H #ifndef macintosh #include #endif #include // define a dboolean typedef int dboolean; //define a signed byte typedef signed char sbyte; //define unsigned types; typedef unsigned char ubyte; #if defined(_WIN32) || defined(macintosh) typedef unsigned short ushort; typedef unsigned int uint; #endif #if defined(_WIN32) || defined(__sun__) // platforms missing (u_)int??_t # include #elif defined(macintosh) // misses (u_)int??_t and does not like SDL_types.h # include typedef SInt16 int16_t; typedef SInt32 int32_t; typedef SInt64 int64_t; typedef UInt16 u_int16_t; typedef UInt32 u_int32_t; typedef UInt64 u_int64_t; #endif // macintosh #if defined(_WIN32) || defined(__sun__) // platforms missing u_int??_t typedef Uint16 u_int16_t; typedef Uint32 u_int32_t; typedef Uint64 u_int64_t; #endif // defined(_WIN32) || defined(__sun__) #ifdef _MSC_VER # include // this is where min and max are defined #endif #ifndef min #define min(a,b) (((a)>(b))?(b):(a)) #endif #ifndef max #define max(a,b) (((a)<(b))?(b):(a)) #endif #ifndef PATH_MAX #define PATH_MAX 4096 #endif #ifndef bool //define a boolean typedef ubyte bool; #endif #ifndef NULL #define NULL 0 #endif // the following stuff has nothing to do with types but needed everywhere, // and since this file is included everywhere, it's here. #if defined(__i386__) || defined(__ia64__) || defined(_WIN32) || \ (defined(__alpha__) || defined(__alpha)) || \ defined(__arm__) || defined(ARM) || \ (defined(__mips__) && defined(__MIPSEL__)) || \ defined(__SYMBIAN32__) || \ defined(__x86_64__) || \ defined(__LITTLE_ENDIAN__) // from physfs_internal.h //# define WORDS_BIGENDIAN 0 #else # define WORDS_BIGENDIAN 1 #endif #ifdef __GNUC__ # define __pack__ __attribute__((packed)) #elif defined(_MSC_VER) # pragma pack(push, packing) # pragma pack(1) # define __pack__ #elif defined(macintosh) # pragma options align=packed # define __pack__ #else # error "This program will not work without packed structures" #endif #ifdef _MSC_VER # define inline __inline #endif #endif //_TYPES_H dxx-rebirth-0.58.1-d1x/include/rbaudio.h000066400000000000000000000042321217717257200177740ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #ifndef _RBAUDIO_H #define _RBAUDIO_H #define RBA_MEDIA_CHANGED -1 typedef struct _RBACHANNELCTL { unsigned int out0in, out0vol; unsigned int out1in, out1vol; unsigned int out2in, out2vol; unsigned int out3in, out3vol; } RBACHANNELCTL; extern void RBAInit(void); extern void RBAExit(); extern long RBAGetDeviceStatus(void); extern int RBAPlayTrack(int track); extern int RBAPlayTracks(int first, int last, void (*hook_finished)(void)); //plays tracks first through last, inclusive extern int RBACheckMediaChange(); extern long RBAGetHeadLoc(int *min, int *sec, int *frame); extern int RBAPeekPlayStatus(void); extern void RBAStop(void); extern void RBAEjectDisk(void); extern void RBASetStereoAudio(RBACHANNELCTL *channels); extern void RBASetQuadAudio(RBACHANNELCTL *channels); extern void RBAGetAudioInfo(RBACHANNELCTL *channels); extern void RBASetChannelVolume(int channel, int volume); extern void RBASetVolume(int volume); extern int RBAEnabled(void); extern void RBADisable(void); extern void RBAEnable(void); extern int RBAGetNumberOfTracks(void); extern void RBACheckFinishedHook(); extern void RBAPause(); extern int RBAResume(); extern int RBAPauseResume(); //return the track number currently playing. Useful if RBAPlayTracks() //is called. Returns 0 if no track playing, else track number int RBAGetTrackNum(); // get the cddb discid for the current cd. unsigned long RBAGetDiscID(); // List the tracks on the CD void RBAList(void); #endif dxx-rebirth-0.58.1-d1x/include/rle.h000066400000000000000000000027771217717257200171450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Protypes for rle functions. * */ #ifndef _RLE_H #define _RLE_H #include "pstypes.h" #include "gr.h" void gr_rle_decode( ubyte * src, ubyte * dest ); int gr_rle_encode( int org_size, ubyte *src, ubyte *dest ); int gr_rle_getsize( int org_size, ubyte *src ); ubyte * gr_rle_find_xth_pixel( ubyte *src, int x,int * count, ubyte color ); int gr_bitmap_rle_compress( grs_bitmap * bmp ); void gr_rle_expand_scanline_masked( ubyte *dest, ubyte *src, int x1, int x2 ); void gr_rle_expand_scanline( ubyte *dest, ubyte *src, int x1, int x2 ); grs_bitmap * rle_expand_texture( grs_bitmap * bmp ); void rle_cache_flush(); void rle_cache_close(); void rle_swap_0_255(grs_bitmap *bmp); void gr_rle_expand_scanline_generic( grs_bitmap * dest, int dx, int dy, ubyte *src, int x1, int x2 ); #endif dxx-rebirth-0.58.1-d1x/include/strio.h000066400000000000000000000002511217717257200175040ustar00rootroot00000000000000/* fileio.c in /misc for d1x file reading */ #ifndef _STRIO_H #define _STRIO_H char* fgets_unlimited(PHYSFS_file *f); char *splitword(char *s, char splitchar); #endif dxx-rebirth-0.58.1-d1x/include/strutil.h000066400000000000000000000034461217717257200200630ustar00rootroot00000000000000#ifndef _STRUTILS_H #define _STRUTILS_H #if defined(macintosh) extern void snprintf(char *out_string, int size, char * format, ... ); #endif extern int d_stricmp( const char *s1, const char *s2 ); extern int d_strnicmp( const char *s1, const char *s2, int n ); extern void d_strlwr( char *s1 ); extern void d_strupr( char *s1 ); extern void d_strrev( char *s1 ); extern char *d_strdup(char *str); // remove extension from filename, doesn't work with paths. void removeext(const char *filename, char *out); //give a filename a new extension, doesn't work with paths with no extension already there extern void change_filename_extension( char *dest, const char *src, char *new_ext ); // split an MS-DOS path into drive, directory path, filename without the extension (base) and extension. // if it's just a filename with no directory specified, this function will get 'base' and 'ext' extern void d_splitpath(char *name, char *drive, char *path, char *base, char *ext); // create a growing 2D array with a single growing buffer for the text // this system is likely to cause less memory fragmentation than having one malloc'd buffer per string int string_array_new(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf); // add a string to a growing 2D array int string_array_add(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf, const char *str); // sort function passed to qsort - also useful for 2d string arrays with individual string pointers int string_array_sort_func(char **e0, char **e1); // reallocate pointers to save memory, sort list alphabetically and remove duplicates according to 'comp' void string_array_tidy(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf, int offset, int (*comp)( const char *, const char * )); #endif /* _STRUTILS_H */ dxx-rebirth-0.58.1-d1x/include/texmap.h000066400000000000000000000153501217717257200176500ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/include/texmap.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:29 $ * * Include file for entities using texture mapper library. * * $Log: texmap.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:29 zicodxx * initial import * * Revision 1.2 1999/07/07 21:21:56 donut * increased recip table size to better accommodate 640 res * * Revision 1.1.1.1 1999/06/14 22:02:20 donut * Import of d1x 1.37 source. * * Revision 1.2 1995/09/04 14:22:10 allender * #defines for fixed point limits on render buffer * * Revision 1.1 1995/05/04 20:14:50 allender * Initial revision * * Revision 1.17 1994/11/10 11:09:16 mike * detail level stuff. * * Revision 1.16 1994/11/09 22:55:32 matt * Added variable Current_seg_depth for detail level optimization * * Revision 1.15 1994/06/09 16:10:04 mike * Add prototype for SC2000 * * Revision 1.14 1994/05/25 18:46:16 matt * Added gr_upoly_tmap_ylr(), which generates ylr's for a polygon * * Revision 1.13 1994/05/25 09:47:12 mike * Added interface support for linear texture mapper (Mike change, Matt commnet) * * Revision 1.12 1994/05/24 17:30:43 mike * Prototype a bunch of linear, vertical scanning functions. * * Revision 1.11 1994/05/19 23:26:14 mike * Add constants NUM_LIGHTING_VALUES, MAX_LIGHTING_VALUE, MIN_LIGHTING_VALUE, * all part of new lighting_values_in_0_to_1 system. * * Revision 1.10 1994/05/14 17:19:21 matt * Added externs * * Revision 1.9 1994/04/13 23:55:44 matt * Increased max_tmap_verts from 16 to 25 * * Revision 1.8 1994/03/31 08:35:43 mike * Prototype for gr_upoly_tmap. * * Revision 1.7 1994/02/08 15:17:54 mike * define label for MAX_TMAP_VERTS * * Revision 1.6 1994/01/31 15:41:51 mike * Add texture_map_lin_lin_sky_v * * Revision 1.5 1994/01/18 10:49:40 mike * prototype for texture_map_lin_lin_sky * * Revision 1.4 1993/11/30 17:09:46 mike * prototype for compute_lighting_value. * * Revision 1.3 1993/11/22 10:50:38 matt * Add ifndef around body of file * * Revision 1.2 1993/10/06 12:41:25 mike * Change prototype for draw_tmap. * * Revision 1.1 1993/09/08 17:29:11 mike * Initial revision * * */ #ifndef _TEXMAP_H #define _TEXMAP_H #include "fix.h" #include "3d.h" #include "gr.h" #define NUM_LIGHTING_LEVELS 32 #define MAX_TMAP_VERTS 25 #define MAX_LIGHTING_VALUE ((NUM_LIGHTING_LEVELS-1)*F1_0/NUM_LIGHTING_LEVELS) #define MIN_LIGHTING_VALUE (F1_0/NUM_LIGHTING_LEVELS) #define FIX_RECIP_TABLE_SIZE 641 //increased from 321 to 641, since this res is now quite achievable.. slight fps boost -MM // ------------------------------------------------------------------------------------------------------- extern fix compute_lighting_value(g3s_point *vertptr); // ------------------------------------------------------------------------------------------------------- // This is the main texture mapper call. // tmap_num references a texture map defined in Texmap_ptrs. // nverts = number of vertices // vertbuf is a pointer to an array of vertex pointers extern void draw_tmap(grs_bitmap *bp, int nverts, g3s_point **vertbuf); //function that takes the same parms as draw_tmap, but renders as flat poly //we need this to do the cloaked effect extern void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf); // ------------------------------------------------------------------------------------------------------- // Texture map vertex. // The fields r,g,b and l are mutually exclusive. r,g,b are used for rgb lighting. // l is used for intensity based lighting. typedef struct g3ds_vertex { fix x,y,z; fix u,v; fix x2d,y2d; fix l; fix r,g,b; } g3ds_vertex; // A texture map is defined as a polygon with u,v coordinates associated with // one point in the polygon, and a pair of vectors describing the orientation // of the texture map in the world, from which the deltas Du_dx, Dv_dy, etc. // are computed. typedef struct g3ds_tmap { int nv; // number of vertices g3ds_vertex verts[MAX_TMAP_VERTS]; // up to 8 vertices, this is inefficient, change } g3ds_tmap; // ------------------------------------------------------------------------------------------------------- // Note: Not all interpolation method and lighting combinations are supported. // Set Interpolation_method to 0/1/2 for linear/linear, perspective/linear, perspective/perspective extern int Interpolation_method; // Set Lighting_on to 0/1/2 for no lighting/intensity lighting/rgb lighting extern int Lighting_on; // HACK INTERFACE: how far away the current segment (& thus texture) is extern int Current_seg_depth; extern int Max_flat_depth; // Deepest segment at which flat shading will be used. (If not flat shading, then what?) // These are pointers to texture maps. If you want to render texture map #7, then you will render // the texture map defined by Texmap_ptrs[7]. extern grs_bitmap Texmap_ptrs[]; extern grs_bitmap Texmap4_ptrs[]; // Interface for sky renderer extern void texture_map_lin_lin_sky(grs_bitmap *srcb, g3ds_tmap *t); extern void texture_map_lin_lin_sky_v(grs_bitmap *srcb, g3ds_tmap *t); extern void texture_map_hyp_lin_v(grs_bitmap *srcb, g3ds_tmap *t); extern void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t); // This is the gr_upoly-like interface to the texture mapper which uses texture-mapper compatible // (ie, avoids cracking) edge/delta computation. void gr_upoly_tmap(int nverts, int *vert ); //This is like gr_upoly_tmap() but instead of drawing, it calls the specified //function with ylr values void gr_upoly_tmap_ylr(int nverts, int *vert, void (*ylr_func)(int, fix, fix) ); extern int Transparency_on,per2_flag; // Set to !0 to enable Sim City 2000 (or Eric's Drive Through, or Eric's Game) specific code. extern int SC2000; extern int Window_clip_left, Window_clip_bot, Window_clip_right, Window_clip_top; // for ugly hack put in to be sure we don't overflow render buffer #define FIX_XLIMIT (639 * F1_0) #define FIX_YLIMIT (479 * F1_0) extern void init_interface_vars_to_assembler(void); #endif dxx-rebirth-0.58.1-d1x/include/timer.h000066400000000000000000000017011217717257200174650ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for timer functions * */ #ifndef _TIMER_H #define _TIMER_H #include "pstypes.h" #include "fix.h" void timer_update(); fix64 timer_query(); void timer_delay(fix seconds); void timer_delay2(int fps); #endif dxx-rebirth-0.58.1-d1x/include/u_mem.h000066400000000000000000000043101217717257200174460ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #ifndef _U_MEM_H #define _U_MEM_H #include #define MEM_K 1.5 // Dynamic array growth factor #ifdef MACINTOSH extern ubyte virtual_memory_on; #endif void mem_init(void); #if !defined(NDEBUG) void mem_display_blocks(); extern void * mem_malloc( unsigned int size, char * var, char * file, int line, int fill_zero ); extern void * mem_realloc( void * buffer, unsigned int size, char * var, char * file, int line ); extern void mem_free( void * buffer ); extern char * mem_strdup(char * str, char * var, char * file, int line ); /* DPH: Changed malloc, etc. to d_malloc. Overloading system calls is very evil and error prone */ #define d_malloc(size) mem_malloc((size),"Unknown", __FILE__,__LINE__, 0 ) #define d_calloc(n,size) mem_malloc((n*size),"Unknown", __FILE__,__LINE__, 1 ) #define d_realloc(ptr,size) mem_realloc((ptr),(size),"Unknown", __FILE__,__LINE__ ) #define d_free(ptr) do{ mem_free(ptr); ptr=NULL; } while(0) #define MALLOC( var, type, count ) (var=(type *)mem_malloc((count)*sizeof(type),#var, __FILE__,__LINE__,0 )) // Checks to see if any blocks are overwritten void mem_validate_heap(); #else #ifdef macintosh extern char *strdup(const char *str); #endif #define d_malloc(size) malloc(size) #define d_calloc(n, size) calloc(n, size) #define d_realloc(ptr,size) realloc(ptr,size) #define d_free(ptr) do{ free(ptr); ptr=NULL; } while(0) #define MALLOC( var, type, count ) (var=(type *)malloc((count)*sizeof(type))) #endif #endif // _U_MEM_H dxx-rebirth-0.58.1-d1x/include/ui.h000066400000000000000000000276411217717257200167750ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header file for user interface * */ #ifndef _UI_H #define _UI_H struct d_event; enum event_type; struct window; typedef struct { char description[100]; char * buttontext[17]; int numkeys; short keycode[100]; int function_number[100]; } UI_KEYPAD; typedef struct { unsigned int frame; int type; int data; } UI_EVENT; #define BASE_GADGET \ short kind; \ struct _gadget * prev; \ struct _gadget * next; \ struct _gadget * when_tab; \ struct _gadget * when_btab; \ struct _gadget * when_up; \ struct _gadget * when_down; \ struct _gadget * when_left; \ struct _gadget * when_right; \ struct _gadget * parent; \ int status; \ int oldstatus; \ grs_canvas * canvas; \ int hotkey; \ short x1,y1,x2,y2; typedef struct _gadget { BASE_GADGET unsigned char rsvd[256]; } UI_GADGET; typedef struct { BASE_GADGET int trap_key; int (*user_function)(void); } UI_GADGET_KEYTRAP; typedef struct { BASE_GADGET short width, height; short b1_held_down; short b1_clicked; short b1_double_clicked; short b1_dragging; short b1_drag_x1, b1_drag_y1; short b1_drag_x2, b1_drag_y2; short b1_done_dragging; int keypress; short mouse_onme; short mouse_x, mouse_y; grs_bitmap * bitmap; } UI_GADGET_USERBOX; typedef struct { BASE_GADGET short width, height; char * text; short position; short oldposition; short pressed; int (*user_function)(void); int (*user_function1)(void); int hotkey1; int dim_if_no_function; } UI_GADGET_BUTTON; typedef struct { BASE_GADGET short width, height; char * text; short length; short slength; short position; short oldposition; short pressed; short first_time; } UI_GADGET_INPUTBOX; typedef struct { BASE_GADGET short width, height; char * text; short position; short oldposition; short pressed; short group; short flag; } UI_GADGET_RADIO; typedef struct { BASE_GADGET char *text; short width, height; sbyte flag; sbyte pressed; sbyte position; sbyte oldposition; int trap_key; int (*user_function)(void); } UI_GADGET_ICON; typedef struct { BASE_GADGET short width, height; char * text; short position; short oldposition; short pressed; short group; short flag; } UI_GADGET_CHECKBOX; typedef struct { BASE_GADGET short horz; short width, height; int start; int stop; int position; int window_size; int fake_length; int fake_position; int fake_size; UI_GADGET_BUTTON * up_button; UI_GADGET_BUTTON * down_button; fix64 last_scrolled; short drag_x, drag_y; int drag_starting; int dragging; int moved; } UI_GADGET_SCROLLBAR; typedef struct { BASE_GADGET short width, height; char **list; int num_items; int num_items_displayed; int first_item; int old_first_item; int current_item; int selected_item; int old_current_item; fix64 last_scrolled; int dragging; int textheight; UI_GADGET_SCROLLBAR * scrollbar; int moved; } UI_GADGET_LISTBOX; enum dialog_flags { DF_BORDER = 1, DF_FILLED = 2, DF_SAVE_BG = 4, DF_DIALOG = (4+2+1), DF_MODAL = 8 // modal = accept all user input exclusively }; typedef struct _ui_window { struct window *wind; int (*callback)(struct _ui_window *, struct d_event *, void *); UI_GADGET * gadget; UI_GADGET * keyboard_focus_gadget; void *userdata; short x, y; short width, height; short text_x, text_y; enum dialog_flags flags; } UI_DIALOG; #define B1_JUST_PRESSED (event->type == EVENT_MOUSE_BUTTON_DOWN && event_mouse_get_button(event) == 0) #define B1_JUST_RELEASED (event->type == EVENT_MOUSE_BUTTON_UP && event_mouse_get_button(event) == 0) #define B1_DOUBLE_CLICKED (event->type == EVENT_MOUSE_DOUBLE_CLICKED && event_mouse_get_button(event) == 0) extern grs_font * ui_small_font; extern unsigned char CBLACK,CGREY,CWHITE,CBRIGHT,CRED; extern UI_GADGET * selected_gadget; extern void Hline(short x1, short x2, short y ); extern void Vline(short y1, short y2, short x ); extern void ui_string_centered( short x, short y, char * s ); extern void ui_draw_box_out( short x1, short y1, short x2, short y2 ); extern void ui_draw_box_in( short x1, short y1, short x2, short y2 ); extern void ui_draw_line_in( short x1, short y1, short x2, short y2 ); extern void ui_draw_frame( short x1, short y1, short x2, short y2 ); extern void ui_draw_shad( short x1, short y1, short x2, short y2, short c1, short c2 ); void ui_init(); void ui_close(); int ui_messagebox( short x, short y, int NumButtons, char * text, ... ); void ui_string_centered( short x, short y, char * s ); int PopupMenu( int NumItems, char * text[] ); extern UI_DIALOG * ui_create_dialog( short x, short y, short w, short h, enum dialog_flags flags, int (*callback)(UI_DIALOG *, struct d_event *, void *), void *userdata ); extern struct window *ui_dialog_get_window(UI_DIALOG *dlg); extern void ui_dialog_set_current_canvas(UI_DIALOG *dlg); extern void ui_close_dialog( UI_DIALOG * dlg ); #define GADGET_PRESSED(g) ((event->type == EVENT_UI_GADGET_PRESSED) && (ui_event_get_gadget(event) == (UI_GADGET *)g)) extern UI_GADGET * ui_gadget_add( UI_DIALOG * dlg, short kind, short x1, short y1, short x2, short y2 ); extern UI_GADGET_BUTTON * ui_add_gadget_button( UI_DIALOG * dlg, short x, short y, short w, short h, char * text, int (*function_to_call)(void) ); extern void ui_gadget_delete_all( UI_DIALOG * dlg ); extern int ui_gadget_send_event(UI_DIALOG *dlg, enum event_type type, UI_GADGET *gadget); extern UI_GADGET *ui_event_get_gadget(struct d_event *event); extern int ui_dialog_do_gadgets( UI_DIALOG * dlg, struct d_event *event ); extern void ui_draw_button( UI_DIALOG *dlg, UI_GADGET_BUTTON * button ); extern int ui_mouse_on_gadget( UI_GADGET * gadget ); extern int ui_button_do( UI_DIALOG *dlg, UI_GADGET_BUTTON * button, struct d_event *event ); extern int ui_listbox_do( UI_DIALOG *dlg, UI_GADGET_LISTBOX * listbox, struct d_event *event ); extern void ui_draw_listbox( UI_DIALOG *dlg, UI_GADGET_LISTBOX * listbox ); extern UI_GADGET_LISTBOX *ui_add_gadget_listbox(UI_DIALOG *dlg, short x, short y, short w, short h, short numitems, char **list); extern void ui_mega_process(); extern void ui_get_button_size( char * text, int * width, int * height ); extern UI_GADGET_SCROLLBAR * ui_add_gadget_scrollbar( UI_DIALOG * dlg, short x, short y, short w, short h, int start, int stop, int position, int window_size ); extern int ui_scrollbar_do( UI_DIALOG *dlg, UI_GADGET_SCROLLBAR * scrollbar, struct d_event *event ); extern void ui_draw_scrollbar( UI_DIALOG *dlg, UI_GADGET_SCROLLBAR * scrollbar ); extern void ui_dprintf( UI_DIALOG * dlg, char * format, ... ); extern void ui_dprintf_at( UI_DIALOG * dlg, short x, short y, char * format, ... ); extern void ui_draw_radio( UI_DIALOG *dlg, UI_GADGET_RADIO * radio ); extern UI_GADGET_RADIO * ui_add_gadget_radio( UI_DIALOG * dlg, short x, short y, short w, short h, short group, char * text ); extern int ui_radio_do( UI_DIALOG *dlg, UI_GADGET_RADIO * radio, struct d_event *event ); extern void ui_radio_set_value(UI_GADGET_RADIO *radio, int value); extern void ui_draw_checkbox( UI_DIALOG *dlg, UI_GADGET_CHECKBOX * checkbox ); extern UI_GADGET_CHECKBOX * ui_add_gadget_checkbox( UI_DIALOG * dlg, short x, short y, short w, short h, short group, char * text ); extern int ui_checkbox_do( UI_DIALOG *dlg, UI_GADGET_CHECKBOX * checkbox, struct d_event *event ); extern void ui_checkbox_check(UI_GADGET_CHECKBOX * checkbox, int check); extern UI_GADGET * ui_gadget_get_prev( UI_GADGET * gadget ); extern UI_GADGET * ui_gadget_get_next( UI_GADGET * gadget ); extern void ui_gadget_calc_keys( UI_DIALOG * dlg); extern void ui_listbox_change(UI_DIALOG *dlg, UI_GADGET_LISTBOX *listbox, short numitems, char **list); extern void ui_draw_inputbox( UI_DIALOG *dlg, UI_GADGET_INPUTBOX * inputbox ); extern UI_GADGET_INPUTBOX * ui_add_gadget_inputbox( UI_DIALOG * dlg, short x, short y, short w, short h, char * text ); extern int ui_inputbox_do( UI_DIALOG *dlg, UI_GADGET_INPUTBOX * inputbox, struct d_event *event ); extern void ui_inputbox_set_text(UI_GADGET_INPUTBOX *inputbox, char *text); extern int ui_userbox_do( UI_DIALOG *dlg, UI_GADGET_USERBOX * userbox, struct d_event *event ); extern UI_GADGET_USERBOX * ui_add_gadget_userbox( UI_DIALOG * dlg, short x, short y, short w, short h ); extern void ui_draw_userbox( UI_DIALOG *dlg, UI_GADGET_USERBOX * userbox ); extern int MenuX( int x, int y, int NumButtons, char * text[] ); char **file_getdirlist(int *NumFiles, char *dir); char **file_getfilelist(int *NumDirs, char *filespec, char *dir); int ui_get_filename( char * filename, char * Filespec, char * message ); void * ui_malloc( int size ); void ui_free( void * buffer ); UI_GADGET_KEYTRAP * ui_add_gadget_keytrap( UI_DIALOG * dlg, int key_to_trap, int (*function_to_call)(void) ); int ui_keytrap_do( UI_GADGET_KEYTRAP * keytrap, struct d_event *event ); #define UI_RECORD_MOUSE 1 #define UI_RECORD_KEYS 2 #define UI_STATUS_NORMAL 0 #define UI_STATUS_RECORDING 1 #define UI_STATUS_PLAYING 2 #define UI_STATUS_FASTPLAY 3 int ui_record_events( int NumberOfEvents, UI_EVENT * buffer, int Flags ); int ui_play_events_realtime( int NumberOfEvents, UI_EVENT * buffer ); int ui_play_events_fast( int NumberOfEvents, UI_EVENT * buffer ); int ui_recorder_status(); void ui_set_playback_speed( int speed ); extern unsigned int ui_number_of_events; extern unsigned int ui_event_counter; int ui_get_file( char * filename, char * Filespec ); int ui_messagebox_n( short xc, short yc, int NumButtons, char * text, char * Button[] ); void ui_draw_icon( UI_GADGET_ICON * icon ); int ui_icon_do( UI_DIALOG *dlg, UI_GADGET_ICON * icon, struct d_event *event ); UI_GADGET_ICON * ui_add_gadget_icon( UI_DIALOG * dlg, char * text, short x, short y, short w, short h, int k,int (*f)(void) ); int GetKeyCode(char * text); int DecodeKeyText( char * text ); void GetKeyDescription( char * text, int keypress ); extern void menubar_init(char * filename ); extern void menubar_close(); extern void menubar_hide(); extern void menubar_show(); void ui_pad_init(); void ui_pad_close(); void ui_pad_activate( UI_DIALOG * dlg, int x, int y ); void ui_pad_deactivate(); void ui_pad_goto(int n); void ui_pad_goto_next(); void ui_pad_goto_prev(); void ui_pad_read( int n, char * filename ); int ui_pad_get_current(); void ui_pad_draw(UI_DIALOG *dlg, int x, int y); void ui_barbox_open( char * text, int length ); void ui_barbox_update( int position ); void ui_barbox_close(); extern int ui_button_any_drawn; #endif dxx-rebirth-0.58.1-d1x/include/vecmat.h000066400000000000000000000305631217717257200176340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header file for vector/matrix library * */ #ifndef _VECMAT_H #define _VECMAT_H #include "maths.h" //#define INLINE 1 //are some of these functions inline? //The basic fixed-point vector. Access elements by name or position typedef struct vms_vector { fix x, y, z; } __pack__ vms_vector; typedef struct vms_vector_array { fix xyz[3]; } __pack__ vms_vector_array; //Short vector, used for pre-rotation points. //Access elements by name or position typedef struct vms_svec { short sv_x, sv_y, sv_z; } __pack__ vms_svec; //Angle vector. Used to store orientations typedef struct vms_angvec { fixang p, b, h; } __pack__ vms_angvec; //A 3x3 rotation matrix. Sorry about the numbering starting with one. //Ordering is across then down, so is the first row typedef struct vms_matrix { vms_vector rvec, uvec, fvec; } __pack__ vms_matrix; // Quaternion structure typedef struct vms_quaternion { signed short w, x, y, z; } __pack__ vms_quaternion; //Macros/functions to fill in fields of structures //macro to check if vector is zero #define IS_VEC_NULL(v) (v->x == 0 && v->y == 0 && v->z == 0) //macro to set a vector to zero. we could do this with an in-line assembly //macro, but it's probably better to let the compiler optimize it. //Note: NO RETURN VALUE #define vm_vec_zero(v) (v)->x=(v)->y=(v)->z=0 //macro set set a matrix to the identity. Note: NO RETURN VALUE // DPH (18/9/98): Begin mod to fix linefeed problem under linux. Uses an // inline function instead of a multi-line macro to fix CR/LF problems. #ifdef __LINUX__ static inline void vm_set_identity(vms_matrix *m) { m->rvec.x = m->uvec.y = m->fvec.z = f1_0; m->rvec.y = m->rvec.z = m->uvec.x = m->uvec.z = m->fvec.x = m->fvec.y = 0; } #else #define vm_set_identity(m) do {m->rvec.x = m->uvec.y = m->fvec.z = f1_0; \ m->rvec.y = m->rvec.z = \ m->uvec.x = m->uvec.z = \ m->fvec.x = m->fvec.y = 0;} while (0) #endif // DPH (19/8/98): End changes. vms_vector * vm_vec_make (vms_vector * v, fix x, fix y, fix z); #ifdef __WATCOMC__ #pragma aux vm_vec_make "*_" parm [eax] [edx] [ebx] [ecx] value [eax] modify exact [] = \ "mov 0[eax],edx" \ "mov 4[eax],ebx" \ "mov 8[eax],ecx"; #endif vms_angvec * vm_angvec_make (vms_angvec * v, fixang p, fixang b, fixang h); #ifdef __WATCOMC__ #pragma aux vm_angvec_make "*_" parm [eax] [dx] [bx] [cx] value [eax] modify exact [] = \ "mov 0[eax],dx" \ "mov 2[eax],bx" \ "mov 4[eax],cx"; #endif //Global constants extern vms_vector vmd_zero_vector; extern vms_matrix vmd_identity_matrix; //Here's a handy constant #define ZERO_VECTOR {0,0,0} #define IDENTITY_MATRIX { {f1_0,0,0}, {0,f1_0,0}, {0,0,f1_0} } //#define vm_vec_make(v,_x,_y,_z) (((v)->x=(_x), (v)->y=(_y), (v)->z=(_z)), (v)) //#pragma off (unreferenced) ////make this local, so compiler can in-line it //static vms_vector *vm_vec_make(vms_vector *v,fix x,fix y,fix z) //{ // v->x = x; // v->y = y; // v->z = z; // // return v; //} //#pragma on (unreferenced) ////macro to fill in elements of a matrix, also for Mike /* #define vm_mat_make(m,_m1,_m2,_m3,_m4,_m5,_m6,_m7,_m8,_m9) \ do { (m)->m1=(_m1); (m)->m2=(_m2); (m)->m3=(_m3); \ (m)->m4=(_m4); (m)->m5=(_m5); (m)->m6=(_m6); \ (m)->m7=(_m7); (m)->m8=(_m8); (m)->m9=(_m9);} while (0) */ #if 0 //kill this, since bogus with new matrix ordering //macro to fill in elements of a matrix, also for Mike #define vm_mat_make(m,_m1,_m2,_m3,_m4,_m5,_m6,_m7,_m8,_m9) \ (((m)->m1 = (_m1), (m)->m2 = (_m2), (m)->m3 = (_m3), \ (m)->m4 = (_m4), (m)->m5 = (_m5), (m)->m6 = (_m6), \ (m)->m7 = (_m7), (m)->m8 = (_m8), (m)->m9 = (_m9)), (m)) #endif /* */ ////fills in fields of an angle vector //#define vm_angvec_make(v,_p,_b,_h) (((v)->p=(_p), (v)->b=(_b), (v)->h=(_h)), (v)) //negate a vector #define vm_vec_negate(v) do {(v)->x = - (v)->x; (v)->y = - (v)->y; (v)->z = - (v)->z;} while (0); //Functions in library #ifndef INLINE //adds two vectors, fills in dest, returns ptr to dest //ok for dest to equal either source, but should use vm_vec_add2() if so vms_vector * vm_vec_add (vms_vector * dest, const vms_vector * src0, const vms_vector * src1); //subs two vectors, fills in dest, returns ptr to dest //ok for dest to equal either source, but should use vm_vec_sub2() if so vms_vector * vm_vec_sub (vms_vector * dest, const vms_vector * src0, const vms_vector * src1); //adds one vector to another. returns ptr to dest //dest can equal source vms_vector * vm_vec_add2 (vms_vector * dest, const vms_vector * src); //subs one vector from another, returns ptr to dest //dest can equal source vms_vector * vm_vec_sub2 (vms_vector * dest, const vms_vector * src); #else /* */ #define vm_vec_add(dest,src0,src1) do { \ (dest)->x = (src0)->x + (src1)->x; \ (dest)->y = (src0)->y + (src1)->y; \ (dest)->z = (src0)->z + (src1)->z; \ } while (0); #define vm_vec_sub(dest,src0,src1) do { \ (dest)->x = (src0)->x - (src1)->x; \ (dest)->y = (src0)->y - (src1)->y; \ (dest)->z = (src0)->z - (src1)->z; \ } while (0); #define vm_vec_add2(dest,src) do { \ (dest)->x += (src)->x; \ (dest)->y += (src)->y; \ (dest)->z += (src)->z; \ } while (0); #define vm_vec_sub2(dest,src) do { \ (dest)->x -= (src)->x; \ (dest)->y -= (src)->y; \ (dest)->z -= (src)->z; \ } while (0); #endif /* */ //averages two vectors. returns ptr to dest //dest can equal either source vms_vector * vm_vec_avg (vms_vector * dest, const vms_vector * src0, const vms_vector * src1); //averages four vectors. returns ptr to dest //dest can equal any source vms_vector * vm_vec_avg4 (vms_vector * dest, const vms_vector * src0, const vms_vector * src1, const vms_vector * src2, const vms_vector * src3); //scales a vector in place. returns ptr to vector vms_vector * vm_vec_scale (vms_vector * dest, fix s); //scales and copies a vector. returns ptr to dest vms_vector * vm_vec_copy_scale (vms_vector * dest, const vms_vector * src, fix s); //scales a vector, adds it to another, and stores in a 3rd vector //dest = src1 + k * src2 vms_vector * vm_vec_scale_add (vms_vector * dest, const vms_vector * src1, const vms_vector * src2, fix k); //scales a vector and adds it to another //dest += k * src vms_vector * vm_vec_scale_add2 (vms_vector * dest, const vms_vector * src, fix k); //scales a vector in place, taking n/d for scale. returns ptr to vector //dest *= n/d vms_vector * vm_vec_scale2 (vms_vector * dest, fix n, fix d); //returns magnitude of a vector fix vm_vec_mag (vms_vector * v); //computes the distance between two points. (does sub and mag) fix vm_vec_dist (const vms_vector * v0, const vms_vector * v1); //computes an approximation of the magnitude of the vector //uses dist = largest + next_largest*3/8 + smallest*3/16 fix vm_vec_mag_quick (vms_vector * v); //computes an approximation of the distance between two points. //uses dist = largest + next_largest*3/8 + smallest*3/16 fix vm_vec_dist_quick (vms_vector * v0, vms_vector * v1); //normalize a vector. returns mag of source vec fix vm_vec_copy_normalize (vms_vector * dest, vms_vector * src); fix vm_vec_normalize (vms_vector * v); //normalize a vector. returns mag of source vec. uses approx mag fix vm_vec_copy_normalize_quick (vms_vector * dest, vms_vector * src); fix vm_vec_normalize_quick (vms_vector * v); //return the normalized direction vector between two points //dest = normalized(end - start). Returns mag of direction vector //NOTE: the order of the parameters matches the vector subtraction fix vm_vec_normalized_dir (vms_vector * dest, vms_vector * end, vms_vector * start); fix vm_vec_normalized_dir_quick (vms_vector * dest, vms_vector * end, vms_vector * start); ////returns dot product of two vectors fix vm_vec_dotprod (const vms_vector * v0, const vms_vector * v1); #define vm_vec_dot(v0,v1) vm_vec_dotprod((v0),(v1)) #ifdef INLINE #ifdef __WATCOMC__ #pragma aux vm_vec_dotprod parm [esi] [edi] value [eax] modify exact [eax ebx ecx edx] = \ "mov eax,[esi]" \ "imul dword ptr [edi]" \ "mov ebx,eax" \ "mov ecx,edx" \ \ "mov eax,4[esi]" \ "imul dword ptr 4[edi]" \ "add ebx,eax" \ "adc ecx,edx" \ \ "mov eax,8[esi]" \ "imul dword ptr 8[edi]" \ "add eax,ebx" \ "adc edx,ecx" \ \ "shrd eax,edx,16"; #endif #endif /* */ //computes cross product of two vectors. returns ptr to dest //dest CANNOT equal either source vms_vector * vm_vec_crossprod (vms_vector * dest, vms_vector * src0, vms_vector * src1); #define vm_vec_cross(dest,src0,src1) vm_vec_crossprod((dest),(src0),(src1)) //computes surface normal from three points. result is normalized //returns ptr to dest //dest CANNOT equal either source vms_vector * vm_vec_normal (vms_vector * dest, vms_vector * p0, vms_vector * p1, vms_vector * p2); //computes non-normalized surface normal from three points. //returns ptr to dest //dest CANNOT equal either source vms_vector * vm_vec_perp (vms_vector * dest, vms_vector * p0, vms_vector * p1, vms_vector * p2); //computes the delta angle between two vectors. //vectors need not be normalized. if they are, call vm_vec_delta_ang_norm() //the forward vector (third parameter) can be NULL, in which case the absolute //value of the angle in returned. Otherwise the angle around that vector is //returned. fixang vm_vec_delta_ang (vms_vector * v0, vms_vector * v1, vms_vector * fvec); //computes the delta angle between two normalized vectors. fixang vm_vec_delta_ang_norm (vms_vector * v0, vms_vector * v1, vms_vector * fvec); //computes a matrix from a set of three angles. returns ptr to matrix vms_matrix * vm_angles_2_matrix (vms_matrix * m, vms_angvec * a); //computes a matrix from a forward vector and an angle vms_matrix * vm_vec_ang_2_matrix (vms_matrix * m, vms_vector * v, fixang a); //computes a matrix from one or more vectors. The forward vector is required, //with the other two being optional. If both up & right vectors are passed, //the up vector is used. If only the forward vector is passed, a bank of //zero is assumed //returns ptr to matrix vms_matrix * vm_vector_2_matrix (vms_matrix * m, vms_vector * fvec, vms_vector * uvec, vms_vector * rvec); //rotates a vector through a matrix. returns ptr to dest vector //dest CANNOT equal either source vms_vector * vm_vec_rotate (vms_vector * dest, const vms_vector * src, const vms_matrix * m); //transpose a matrix in place. returns ptr to matrix vms_matrix * vm_transpose_matrix (vms_matrix * m); #define vm_transpose(m) vm_transpose_matrix(m) //copy and transpose a matrix. returns ptr to matrix //dest CANNOT equal source. use vm_transpose_matrix() if this is the case vms_matrix * vm_copy_transpose_matrix (vms_matrix * dest, vms_matrix * src); #define vm_copy_transpose(dest,src) vm_copy_transpose_matrix((dest),(src)) //mulitply 2 matrices, fill in dest. returns ptr to dest //dest CANNOT equal either source vms_matrix * vm_matrix_x_matrix (vms_matrix * dest, vms_matrix * src0, vms_matrix * src1); //extract angles from a matrix vms_angvec * vm_extract_angles_matrix (vms_angvec * a, vms_matrix * m); //extract heading and pitch from a vector, assuming bank==0 vms_angvec * vm_extract_angles_vector (vms_angvec * a, vms_vector * v); //compute the distance from a point to a plane. takes the normalized normal //of the plane (ebx), a point on the plane (edi), and the point to check (esi). //returns distance in eax //distance is signed, so negative dist is on the back of the plane fix vm_dist_to_plane (const vms_vector * checkp, const vms_vector * norm, const vms_vector * planep); //fills in fields of an angle vector #define vm_angvec_make(v,_p,_b,_h) (((v)->p=(_p), (v)->b=(_b), (v)->h=(_h)), (v)) // convert from quaternion to vector matrix and back void vms_quaternion_from_matrix(vms_quaternion * q, const vms_matrix * m); void vms_matrix_from_quaternion(vms_matrix * m, const vms_quaternion * q); #endif dxx-rebirth-0.58.1-d1x/main/000077500000000000000000000000001217717257200154765ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/main/ai.c000066400000000000000000003421141217717257200162400ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Autonomous Individual movement. * */ #include #include #include "inferno.h" #include "game.h" #include "console.h" #include "3d.h" #include "object.h" #include "render.h" #include "dxxerror.h" #include "ai.h" #include "laser.h" #include "fvi.h" #include "polyobj.h" #include "bm.h" #include "weapon.h" #include "physics.h" #include "collide.h" #include "fuelcen.h" #include "player.h" #include "wall.h" #include "vclip.h" #include "digi.h" #include "fireball.h" #include "morph.h" #include "effects.h" #include "timer.h" #include "sounds.h" #include "cntrlcen.h" #include "multibot.h" #include "multi.h" #include "gameseq.h" #include "key.h" #include "powerup.h" #include "gauges.h" #include "text.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif #ifndef NDEBUG #include "string.h" #ifdef __MSDOS__ #include #endif #endif //added 05/17/99 Matt Mueller #include "u_mem.h" //end addition -MM void init_boss_segments(short segptr[], int *num_segs, int size_check); void ai_multi_send_robot_position(int objnum, int force); #define PARALLAX 0 // If !0, then special debugging info for Parallax eyes only enabled. #define MIN_D 0x100 enum { Flinch_scale = 4, Attack_scale = 24, }; #define ANIM_RATE (F1_0/16) #define DELTA_ANG_SCALE 16 static const sbyte Mike_to_matt_xlate[] = {AS_REST, AS_REST, AS_ALERT, AS_ALERT, AS_FLINCH, AS_FIRE, AS_RECOIL, AS_REST}; // int No_ai_flag=0; #define OVERALL_AGITATION_MAX 100 #define MAX_AI_CLOAK_INFO 8 // Must be a power of 2! #define BOSS_CLOAK_DURATION (F1_0*7) #define BOSS_DEATH_DURATION (F1_0*6) #define BOSS_DEATH_SOUND_DURATION 0x2ae14 // 2.68 seconds // Amount of time since the current robot was last processed for things such as movement. // It is not valid to use FrameTime because robots do not get moved every frame. //fix AI_proc_time; int Num_boss_teleport_segs; short Boss_teleport_segs[MAX_BOSS_TELEPORT_SEGS]; #ifndef SHAREWARE int Num_boss_gate_segs; short Boss_gate_segs[MAX_BOSS_TELEPORT_SEGS]; #endif // ---------- John: These variables must be saved as part of gamesave. ---------- int Ai_initialized = 0; int Overall_agitation; ai_local Ai_local_info[MAX_OBJECTS]; point_seg Point_segs[MAX_POINT_SEGS]; point_seg *Point_segs_free_ptr = Point_segs; ai_cloak_info Ai_cloak_info[MAX_AI_CLOAK_INFO]; fix64 Boss_cloak_start_time = 0; fix64 Boss_cloak_end_time = 0; fix64 Last_teleport_time = 0; fix Boss_teleport_interval = F1_0*8; fix Boss_cloak_interval = F1_0*10; // Time between cloaks fix Boss_cloak_duration = BOSS_CLOAK_DURATION; fix64 Last_gate_time = 0; fix Gate_interval = F1_0*6; fix64 Boss_dying_start_time; int Boss_dying, Boss_dying_sound_playing, Boss_hit_this_frame; int Boss_been_hit=0; // ---------- John: End of variables which must be saved as part of gamesave. ---------- int ai_evaded=0; #ifndef SHAREWARE // 0 mech // 1 green claw // 2 spider // 3 josh // 4 violet // 5 cloak vulcan // 6 cloak mech // 7 brain // 8 onearm // 9 plasma // 10 toaster // 11 bird // 12 missile bird // 13 polyhedron // 14 baby spider // 15 mini boss // 16 super mech // 17 shareware boss // 18 cloak-green ; note, gating in this guy benefits player, cloak objects // 19 vulcan // 20 toad // 21 4-claw // 22 quad-laser // 23 super boss // byte Super_boss_gate_list[] = {0, 1, 2, 9, 11, 16, 18, 19, 21, 22, 0, 9, 9, 16, 16, 18, 19, 19, 22, 22}; sbyte Super_boss_gate_list[] = {0, 1, 8, 9, 10, 11, 12, 15, 16, 18, 19, 20, 22, 0, 8, 11, 19, 20, 8, 20, 8}; #define MAX_GATE_INDEX ( sizeof(Super_boss_gate_list) / sizeof(Super_boss_gate_list[0]) ) #endif int Ai_info_enabled=0; #define MAX_AWARENESS_EVENTS 64 typedef struct awareness_event { short segnum; // segment the event occurred in short type; // type of event, defines behavior vms_vector pos; // absolute 3 space location of event } awareness_event; // These globals are set by a call to find_vector_intersection, which is a slow routine, // so we don't want to call it again (for this object) unless we have to. vms_vector Hit_pos; int Hit_type, Hit_seg; fvi_info Hit_data; int Num_awareness_events = 0; awareness_event Awareness_events[MAX_AWARENESS_EVENTS]; vms_vector Believed_player_pos; #define AIS_MAX 8 #define AIE_MAX 4 #ifndef NDEBUG // Index into this array with ailp->mode char mode_text[8][9] = { "STILL ", "WANDER ", "FOL_PATH", "CHASE_OB", "RUN_FROM", "HIDE ", "FOL_PAT2", "OPENDOR2" }; // Index into this array with aip->behavior char behavior_text[6][9] = { "STILL ", "NORMAL ", "HIDE ", "RUN_FROM", "FOLPATH ", "STATION " }; // Index into this array with aip->GOAL_STATE or aip->CURRENT_STATE char state_text[8][5] = { "NONE", "REST", "SRCH", "LOCK", "FLIN", "FIRE", "RECO", "ERR_", }; int Ai_animation_test=0; #endif // Current state indicates where the robot current is, or has just done. // Transition table between states for an AI object. // First dimension is trigger event. // Second dimension is current state. // Third dimension is goal state. // Result is new goal state. // ERR_ means something impossible has happened. static const sbyte Ai_transition_table[AI_MAX_EVENT][AI_MAX_STATE][AI_MAX_STATE] = { { // Event = AIE_FIRE, a nearby object fired // none rest srch lock flin fire reco // CURRENT is rows, GOAL is columns { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO }, // none { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO }, // rest { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO }, // search { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO }, // lock { AIS_ERR_, AIS_REST, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FIRE, AIS_RECO }, // flinch { AIS_ERR_, AIS_FIRE, AIS_FIRE, AIS_FIRE, AIS_FLIN, AIS_FIRE, AIS_RECO }, // fire { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_FIRE } // recoil }, // Event = AIE_HITT, a nearby object was hit (or a wall was hit) { { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_REST, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_FIRE} }, // Event = AIE_COLL, player collided with robot { { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_LOCK, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_REST, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FIRE, AIS_RECO}, { AIS_ERR_, AIS_LOCK, AIS_LOCK, AIS_LOCK, AIS_FLIN, AIS_FIRE, AIS_FIRE} }, // Event = AIE_HURT, player hurt robot (by firing at and hitting it) // Note, this doesn't necessarily mean the robot JUST got hit, only that that is the most recent thing that happened. { { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN}, { AIS_ERR_, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN, AIS_FLIN} } }; // --------------------------------------------------------------------------------------------------------------------- // Given a behavior, set initial mode. int ai_behavior_to_mode(int behavior) { switch (behavior) { case AIB_STILL: return AIM_STILL; case AIB_NORMAL: return AIM_CHASE_OBJECT; case AIB_HIDE: return AIM_HIDE; case AIB_RUN_FROM: return AIM_RUN_FROM_OBJECT; case AIB_FOLLOW_PATH: return AIM_FOLLOW_PATH; case AIB_STATION: return AIM_STILL; default: Int3(); // Contact Mike: Error, illegal behavior type } return AIM_STILL; } // --------------------------------------------------------------------------------------------------------------------- // Call every time the player starts a new ship. void ai_init_boss_for_ship(void) { Boss_been_hit = 0; } // --------------------------------------------------------------------------------------------------------------------- // initial_mode == -1 means leave mode unchanged. void init_ai_object(int objnum, int behavior, int hide_segment) { object *objp = &Objects[objnum]; ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objnum]; memset(ailp, 0, sizeof(ai_local)); #ifdef DEST_SAT if (!(Game_mode & GM_MULTI) && Robot_info[objp->id].boss_flag) { if (Current_level_num != Last_level) { objp->id = 0; objp->flags |= OF_SHOULD_BE_DEAD; } } #endif if (behavior == 0) { behavior = AIB_NORMAL; objp->ctype.ai_info.behavior = behavior; } // mode is now set from the Robot dialog, so this should get overwritten. ailp->mode = AIM_STILL; ailp->previous_visibility = 0; if (behavior != -1) { aip->behavior = behavior; ailp->mode = ai_behavior_to_mode(aip->behavior); } else if (!((aip->behavior >= MIN_BEHAVIOR) && (aip->behavior <= MAX_BEHAVIOR))) { aip->behavior = AIB_NORMAL; } // This is astonishingly stupid! This routine gets called by matcens! KILL KILL KILL!!! Point_segs_free_ptr = Point_segs; vm_vec_zero(&objp->mtype.phys_info.velocity); // -- ailp->wait_time = F1_0*5; ailp->player_awareness_time = 0; ailp->player_awareness_type = 0; aip->GOAL_STATE = AIS_SRCH; aip->CURRENT_STATE = AIS_REST; ailp->time_player_seen = GameTime64; ailp->next_misc_sound_time = GameTime64; ailp->time_player_sound_attacked = GameTime64; if ((behavior == AIB_HIDE) || (behavior == AIB_FOLLOW_PATH) || (behavior == AIB_STATION) || (behavior == AIB_RUN_FROM)) { aip->hide_segment = hide_segment; ailp->goal_segment = hide_segment; aip->hide_index = -1; // This means the path has not yet been created. aip->cur_path_index = 0; } aip->SKIP_AI_COUNT = 0; if (Robot_info[objp->id].cloak_type == RI_CLOAKED_ALWAYS) aip->CLOAKED = 1; else aip->CLOAKED = 0; objp->mtype.phys_info.flags |= (PF_BOUNCE | PF_TURNROLL); aip->REMOTE_OWNER = -1; aip->danger_laser_num = -1; } // --------------------------------------------------------------------------------------------------------------------- void init_ai_objects(void) { int i; Point_segs_free_ptr = Point_segs; for (i=0; icontrol_type == CT_AI) init_ai_object(i, objp->ctype.ai_info.behavior, objp->ctype.ai_info.hide_segment); } init_boss_segments(Boss_teleport_segs, &Num_boss_teleport_segs, 1); #ifndef SHAREWARE init_boss_segments(Boss_gate_segs, &Num_boss_gate_segs, 0); #endif Boss_dying_sound_playing = 0; Boss_dying = 0; Boss_been_hit = 0; #ifndef SHAREWARE Gate_interval = F1_0*5 - Difficulty_level*F1_0/2; #endif Ai_initialized = 1; } // ---------------------------------------------------------------- // Do *dest = *delta unless: // *delta is pretty small // and they are of different signs. void set_rotvel_and_saturate(fix *dest, fix delta) { if ((delta ^ *dest) < 0) { if (abs(delta) < F1_0/8) { *dest = delta/4; } else *dest = delta; } else { *dest = delta; } } //--debug-- #ifndef NDEBUG //--debug-- int Total_turns=0; //--debug-- int Prevented_turns=0; //--debug-- #endif #define AI_TURN_SCALE 1 #define BABY_SPIDER_ID 14 extern void physics_turn_towards_vector(vms_vector *goal_vector, object *obj, fix rate); //------------------------------------------------------------------------------------------- void ai_turn_towards_vector(vms_vector *goal_vector, object *objp, fix rate) { vms_vector new_fvec; fix dot; if ((objp->id == BABY_SPIDER_ID) && (objp->type == OBJ_ROBOT)) { physics_turn_towards_vector(goal_vector, objp, rate); return; } new_fvec = *goal_vector; dot = vm_vec_dot(goal_vector, &objp->orient.fvec); if (dot < (F1_0 - FrameTime/2)) { fix mag; fix new_scale = fixdiv(FrameTime * AI_TURN_SCALE, rate); vm_vec_scale(&new_fvec, new_scale); vm_vec_add2(&new_fvec, &objp->orient.fvec); mag = vm_vec_normalize_quick(&new_fvec); if (mag < F1_0/256) { new_fvec = *goal_vector; // if degenerate vector, go right to goal } } vm_vector_2_matrix(&objp->orient, &new_fvec, NULL, &objp->orient.rvec); } // -------------------------------------------------------------------------------------------------------------------- void ai_turn_randomly(vms_vector *vec_to_player, object *obj, fix rate, int previous_visibility) { vms_vector curvec; // Random turning looks too stupid, so 1/4 of time, cheat. if (previous_visibility) if (d_rand() > 0x7400) { ai_turn_towards_vector(vec_to_player, obj, rate); return; } //--debug-- if (d_rand() > 0x6000) //--debug-- Prevented_turns++; curvec = obj->mtype.phys_info.rotvel; curvec.y += F1_0/64; curvec.x += curvec.y/6; curvec.y += curvec.z/4; curvec.z += curvec.x/10; if (abs(curvec.x) > F1_0/8) curvec.x /= 4; if (abs(curvec.y) > F1_0/8) curvec.y /= 4; if (abs(curvec.z) > F1_0/8) curvec.z /= 4; obj->mtype.phys_info.rotvel = curvec; } // Overall_agitation affects: // Widens field of view. Field of view is in range 0..1 (specified in bitmaps.tbl as N/360 degrees). // Overall_agitation/128 subtracted from field of view, making robots see wider. // Increases distance to which robot will search to create path to player by Overall_agitation/8 segments. // Decreases wait between fire times by Overall_agitation/64 seconds. // -------------------------------------------------------------------------------------------------------------------- // Returns: // 0 Player is not visible from object, obstruction or something. // 1 Player is visible, but not in field of view. // 2 Player is visible and in field of view. // Note: Uses Believed_player_pos as player's position for cloak effect. // NOTE: Will destructively modify *pos if *pos is outside the mine. int player_is_visible_from_object(object *objp, vms_vector *pos, fix field_of_view, vms_vector *vec_to_player) { fix dot; fvi_query fq; fq.p0 = pos; if ((pos->x != objp->pos.x) || (pos->y != objp->pos.y) || (pos->z != objp->pos.z)) { int segnum = find_point_seg(pos, objp->segnum); if (segnum == -1) { fq.startseg = objp->segnum; *pos = objp->pos; con_printf(CON_DEBUG, "Object %hu, gun is outside mine, moving towards center.\n", (unsigned short)(objp-Objects)); move_towards_segment_center(objp); } else fq.startseg = segnum; } else fq.startseg = objp->segnum; fq.p1 = &Believed_player_pos; fq.rad = F1_0/4; fq.thisobjnum = objp-Objects; fq.ignore_obj_list = NULL; fq.flags = FQ_TRANSWALL | FQ_CHECK_OBJS; //what about trans walls??? Hit_type = find_vector_intersection(&fq,&Hit_data); Hit_pos = Hit_data.hit_pnt; Hit_seg = Hit_data.hit_seg; if ((Hit_type == HIT_NONE) || ((Hit_type == HIT_OBJECT) && (Hit_data.hit_object == Players[Player_num].objnum))) { dot = vm_vec_dot(vec_to_player, &objp->orient.fvec); if (dot > field_of_view - (Overall_agitation << 9)) { return 2; } else { return 1; } } else { return 0; } } // ------------------------------------------------------------------------------------------------------------------ // Return 1 if animates, else return 0 int do_silly_animation(object *objp) { int objnum = objp-Objects; const jointpos *jp_list; int robot_type, gun_num, robot_state, num_joint_positions; polyobj_info *pobj_info = &objp->rtype.pobj_info; ai_static *aip = &objp->ctype.ai_info; // ai_local *ailp = &Ai_local_info[objnum]; int num_guns, at_goal; int attack_type; int flinch_attack_scale = 1; robot_type = objp->id; num_guns = Robot_info[robot_type].n_guns; attack_type = Robot_info[robot_type].attack_type; if (num_guns == 0) { return 0; } // This is a hack. All positions should be based on goal_state, not GOAL_STATE. robot_state = Mike_to_matt_xlate[aip->GOAL_STATE]; // previous_robot_state = Mike_to_matt_xlate[aip->CURRENT_STATE]; if (attack_type) // && ((robot_state == AS_FIRE) || (robot_state == AS_RECOIL))) flinch_attack_scale = Attack_scale; else if ((robot_state == AS_FLINCH) || (robot_state == AS_RECOIL)) flinch_attack_scale = Flinch_scale; at_goal = 1; for (gun_num=0; gun_num <= num_guns; gun_num++) { int joint; num_joint_positions = robot_get_anim_state(&jp_list, robot_type, gun_num, robot_state); for (joint=0; jointanim_angles[jointnum]; if (jointnum >= Polygon_models[objp->rtype.pobj_info.model_num].n_models) { //Int3(); // Contact Mike: incompatible data, illegal jointnum, problem in pof file? continue; } if (jp->p != pobjp->p) { if (gun_num == 0) at_goal = 0; Ai_local_info[objnum].goal_angles[jointnum].p = jp->p; delta_angle = jp->p - pobjp->p; if (delta_angle >= F1_0/2) delta_2 = -ANIM_RATE; else if (delta_angle >= 0) delta_2 = ANIM_RATE; else if (delta_angle >= -F1_0/2) delta_2 = -ANIM_RATE; else delta_2 = ANIM_RATE; if (flinch_attack_scale != 1) delta_2 *= flinch_attack_scale; Ai_local_info[objnum].delta_angles[jointnum].p = delta_2/DELTA_ANG_SCALE; // complete revolutions per second } if (jp->b != pobjp->b) { if (gun_num == 0) at_goal = 0; Ai_local_info[objnum].goal_angles[jointnum].b = jp->b; delta_angle = jp->b - pobjp->b; if (delta_angle >= F1_0/2) delta_2 = -ANIM_RATE; else if (delta_angle >= 0) delta_2 = ANIM_RATE; else if (delta_angle >= -F1_0/2) delta_2 = -ANIM_RATE; else delta_2 = ANIM_RATE; if (flinch_attack_scale != 1) delta_2 *= flinch_attack_scale; Ai_local_info[objnum].delta_angles[jointnum].b = delta_2/DELTA_ANG_SCALE; // complete revolutions per second } if (jp->h != pobjp->h) { if (gun_num == 0) at_goal = 0; Ai_local_info[objnum].goal_angles[jointnum].h = jp->h; delta_angle = jp->h - pobjp->h; if (delta_angle >= F1_0/2) delta_2 = -ANIM_RATE; else if (delta_angle >= 0) delta_2 = ANIM_RATE; else if (delta_angle >= -F1_0/2) delta_2 = -ANIM_RATE; else delta_2 = ANIM_RATE; if (flinch_attack_scale != 1) delta_2 *= flinch_attack_scale; Ai_local_info[objnum].delta_angles[jointnum].h = delta_2/DELTA_ANG_SCALE; // complete revolutions per second } } if (at_goal) { //ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objp-Objects]; ailp->achieved_state[gun_num] = ailp->goal_state[gun_num]; if (ailp->achieved_state[gun_num] == AIS_RECO) ailp->goal_state[gun_num] = AIS_FIRE; if (ailp->achieved_state[gun_num] == AIS_FLIN) ailp->goal_state[gun_num] = AIS_LOCK; } } if (at_goal == 1) //num_guns) aip->CURRENT_STATE = aip->GOAL_STATE; return 1; } // ------------------------------------------------------------------------------------------ // Move all sub-objects in an object towards their goals. // Current orientation of object is at: pobj_info.anim_angles // Goal orientation of object is at: ai_info.goal_angles // Delta orientation of object is at: ai_info.delta_angles void ai_frame_animation(object *objp) { int objnum = objp-Objects; int joint; int num_joints; num_joints = Polygon_models[objp->rtype.pobj_info.model_num].n_models; for (joint=1; jointrtype.pobj_info.anim_angles[joint]; vms_angvec *goalangp = &Ai_local_info[objnum].goal_angles[joint]; vms_angvec *deltaangp = &Ai_local_info[objnum].delta_angles[joint]; #ifndef NDEBUG if (Ai_animation_test) { con_printf(CON_DEBUG, "%i: [%7.3f %7.3f %7.3f] [%7.3f %7.3f %7.3f]\n", joint, f2fl(curangp->p), f2fl(curangp->b), f2fl(curangp->h), f2fl(goalangp->p), f2fl(goalangp->b), f2fl(goalangp->h)); } #endif delta_to_goal = goalangp->p - curangp->p; if (delta_to_goal > 32767) delta_to_goal = delta_to_goal - 65536; else if (delta_to_goal < -32767) delta_to_goal = 65536 + delta_to_goal; if (delta_to_goal) { scaled_delta_angle = fixmul(deltaangp->p, FrameTime) * DELTA_ANG_SCALE; curangp->p += scaled_delta_angle; if (abs(delta_to_goal) < abs(scaled_delta_angle)) curangp->p = goalangp->p; } delta_to_goal = goalangp->b - curangp->b; if (delta_to_goal > 32767) delta_to_goal = delta_to_goal - 65536; else if (delta_to_goal < -32767) delta_to_goal = 65536 + delta_to_goal; if (delta_to_goal) { scaled_delta_angle = fixmul(deltaangp->b, FrameTime) * DELTA_ANG_SCALE; curangp->b += scaled_delta_angle; if (abs(delta_to_goal) < abs(scaled_delta_angle)) curangp->b = goalangp->b; } delta_to_goal = goalangp->h - curangp->h; if (delta_to_goal > 32767) delta_to_goal = delta_to_goal - 65536; else if (delta_to_goal < -32767) delta_to_goal = 65536 + delta_to_goal; if (delta_to_goal) { scaled_delta_angle = fixmul(deltaangp->h, FrameTime) * DELTA_ANG_SCALE; curangp->h += scaled_delta_angle; if (abs(delta_to_goal) < abs(scaled_delta_angle)) curangp->h = goalangp->h; } } } // ---------------------------------------------------------------------------------- void set_next_fire_time(ai_local *ailp, robot_info *robptr) { ailp->rapidfire_count++; if (ailp->rapidfire_count < robptr->rapidfire_count[Difficulty_level]) { ailp->next_fire = min(F1_0/8, robptr->firing_wait[Difficulty_level]/2); } else { ailp->rapidfire_count = 0; ailp->next_fire = robptr->firing_wait[Difficulty_level]; } } // ---------------------------------------------------------------------------------- // When some robots collide with the player, they attack. // If player is cloaked, then robot probably didn't actually collide, deal with that here. void do_ai_robot_hit_attack(object *robot, object *player, vms_vector *collision_point) { ai_local *ailp = &Ai_local_info[robot-Objects]; robot_info *robptr = &Robot_info[robot->id]; //#ifndef NDEBUG if (cheats.robotfiringsuspended) return; //#endif // If player is dead, stop firing. if (Objects[Players[Player_num].objnum].type == OBJ_GHOST) return; if (robptr->attack_type == 1) { if (ailp->next_fire <= 0) { if (!(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) if (vm_vec_dist_quick(&ConsoleObject->pos, &robot->pos) < robot->size + ConsoleObject->size + F1_0*2) collide_player_and_nasty_robot( player, robot, collision_point ); robot->ctype.ai_info.GOAL_STATE = AIS_RECO; set_next_fire_time(ailp, robptr); } } } extern int Player_exploded; // -------------------------------------------------------------------------------------------------------------------- // Note: Parameter vec_to_player is only passed now because guns which aren't on the forward vector from the // center of the robot will not fire right at the player. We need to aim the guns at the player. Barring that, we cheat. // When this routine is complete, the parameter vec_to_player should not be necessary. void ai_fire_laser_at_player(object *obj, vms_vector *fire_point) { int objnum = obj-Objects; ai_local *ailp = &Ai_local_info[objnum]; robot_info *robptr = &Robot_info[obj->id]; vms_vector fire_vec; vms_vector bpp_diff; if (cheats.robotfiringsuspended) return; #ifndef NDEBUG // We should never be coming here for the green guy, as he has no laser! if (robptr->attack_type == 1) Int3(); // Contact Mike: This is impossible. #endif if (obj->control_type == CT_MORPH) return; // If player is exploded, stop firing. if (Player_exploded) return; // If player is cloaked, maybe don't fire based on how long cloaked and randomness. if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { fix64 cloak_time = Ai_cloak_info[objnum % MAX_AI_CLOAK_INFO].last_time; if (GameTime64 - cloak_time > CLOAK_TIME_MAX/4) if (d_rand() > fixdiv(GameTime64 - cloak_time, CLOAK_TIME_MAX)/2) { set_next_fire_time(ailp, robptr); return; } } //-- // Find segment containing laser fire position. If the robot is straddling a segment, the position from //-- // which it fires may be in a different segment, which is bad news for find_vector_intersection. So, cast //-- // a ray from the object center (whose segment we know) to the laser position. Then, in the call to Laser_create_new //-- // use the data returned from this call to find_vector_intersection. //-- // Note that while find_vector_intersection is pretty slow, it is not terribly slow if the destination point is //-- // in the same segment as the source point. //-- //-- fq.p0 = &obj->pos; //-- fq.startseg = obj->segnum; //-- fq.p1 = fire_point; //-- fq.rad = 0; //-- fq.thisobjnum = obj-Objects; //-- fq.ignore_obj_list = NULL; //-- fq.flags = FQ_TRANSWALL | FQ_CHECK_OBJS; //what about trans walls??? //-- //-- fate = find_vector_intersection(&fq, &hit_data); //-- if (fate != HIT_NONE) //-- return; // Set position to fire at based on difficulty level. bpp_diff.x = Believed_player_pos.x + (d_rand()-16384) * (NDL-Difficulty_level-1) * 4; bpp_diff.y = Believed_player_pos.y + (d_rand()-16384) * (NDL-Difficulty_level-1) * 4; bpp_diff.z = Believed_player_pos.z + (d_rand()-16384) * (NDL-Difficulty_level-1) * 4; // Half the time fire at the player, half the time lead the player. if (d_rand() > 16384) { vm_vec_normalized_dir_quick(&fire_vec, &bpp_diff, fire_point); } else { vms_vector player_direction_vector; vm_vec_sub(&player_direction_vector, &bpp_diff, &bpp_diff); // If player is not moving, fire right at him! // Note: If the robot fires in the direction of its forward vector, this is bad because the weapon does not // come out from the center of the robot; it comes out from the side. So it is common for the weapon to miss // its target. Ideally, we want to point the guns at the player. For now, just fire right at the player. if ((abs(player_direction_vector.x < 0x10000)) && (abs(player_direction_vector.y < 0x10000)) && (abs(player_direction_vector.z < 0x10000))) { vm_vec_normalized_dir_quick(&fire_vec, &bpp_diff, fire_point); // Player is moving. Determine where the player will be at the end of the next frame if he doesn't change his // behavior. Fire at exactly that point. This isn't exactly what you want because it will probably take the laser // a different amount of time to get there, since it will probably be a different distance from the player. // So, that's why we write games, instead of guiding missiles... } else { vm_vec_sub(&fire_vec, &bpp_diff, fire_point); vm_vec_scale(&fire_vec,fixmul(Weapon_info[Robot_info[obj->id].weapon_type].speed[Difficulty_level], FrameTime)); vm_vec_add2(&fire_vec, &player_direction_vector); vm_vec_normalize_quick(&fire_vec); } } Laser_create_new_easy( &fire_vec, fire_point, obj-Objects, robptr->weapon_type, 1); #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) { ai_multi_send_robot_position(objnum, -1); multi_send_robot_fire(objnum, obj->ctype.ai_info.CURRENT_GUN, &fire_vec); } #endif #endif create_awareness_event(obj, PA_NEARBY_ROBOT_FIRED); set_next_fire_time(ailp, robptr); // If the boss fired, allow him to teleport very soon (right after firing, cool!), pending other factors. if (robptr->boss_flag) Last_teleport_time -= Boss_teleport_interval/2; } // -------------------------------------------------------------------------------------------------------------------- // vec_goal must be normalized, or close to it. void move_towards_vector(object *objp, vms_vector *vec_goal) { physics_info *pptr = &objp->mtype.phys_info; fix speed, dot, max_speed; robot_info *robptr = &Robot_info[objp->id]; vms_vector vel; // Trying to move towards player. If forward vector much different than velocity vector, // bash velocity vector twice as much towards player as usual. vel = pptr->velocity; vm_vec_normalize_quick(&vel); dot = vm_vec_dot(&vel, &objp->orient.fvec); if (dot < 3*F1_0/4) { // This funny code is supposed to slow down the robot and move his velocity towards his direction // more quickly than the general code pptr->velocity.x = pptr->velocity.x/2 + fixmul(vec_goal->x, FrameTime*32); pptr->velocity.y = pptr->velocity.y/2 + fixmul(vec_goal->y, FrameTime*32); pptr->velocity.z = pptr->velocity.z/2 + fixmul(vec_goal->z, FrameTime*32); } else { pptr->velocity.x += fixmul(vec_goal->x, FrameTime*64) * (Difficulty_level+5)/4; pptr->velocity.y += fixmul(vec_goal->y, FrameTime*64) * (Difficulty_level+5)/4; pptr->velocity.z += fixmul(vec_goal->z, FrameTime*64) * (Difficulty_level+5)/4; } speed = vm_vec_mag_quick(&pptr->velocity); max_speed = robptr->max_speed[Difficulty_level]; // Green guy attacks twice as fast as he moves away. if (robptr->attack_type == 1) max_speed *= 2; if (speed > max_speed) { pptr->velocity.x = (pptr->velocity.x*3)/4; pptr->velocity.y = (pptr->velocity.y*3)/4; pptr->velocity.z = (pptr->velocity.z*3)/4; } } // -------------------------------------------------------------------------------------------------------------------- void move_towards_player(object *objp, vms_vector *vec_to_player) // vec_to_player must be normalized, or close to it. { move_towards_vector(objp, vec_to_player); } // -------------------------------------------------------------------------------------------------------------------- // I am ashamed of this: fast_flag == -1 means normal slide about. fast_flag = 0 means no evasion. void move_around_player(object *objp, vms_vector *vec_to_player, int fast_flag) { physics_info *pptr = &objp->mtype.phys_info; fix speed; robot_info *robptr = &Robot_info[objp->id]; int dir; vms_vector evade_vector; if (fast_flag == 0) return; dir = ((objp-Objects) ^ ((d_tick_count + 3*(objp-Objects)) >> 5)) & 3; Assert((dir >= 0) && (dir <= 3)); switch (dir) { case 0: evade_vector.x = fixmul(vec_to_player->z, FrameTime*32); evade_vector.y = fixmul(vec_to_player->y, FrameTime*32); evade_vector.z = fixmul(-vec_to_player->x, FrameTime*32); break; case 1: evade_vector.x = fixmul(-vec_to_player->z, FrameTime*32); evade_vector.y = fixmul(vec_to_player->y, FrameTime*32); evade_vector.z = fixmul(vec_to_player->x, FrameTime*32); break; case 2: evade_vector.x = fixmul(-vec_to_player->y, FrameTime*32); evade_vector.y = fixmul(vec_to_player->x, FrameTime*32); evade_vector.z = fixmul(vec_to_player->z, FrameTime*32); break; case 3: evade_vector.x = fixmul(vec_to_player->y, FrameTime*32); evade_vector.y = fixmul(-vec_to_player->x, FrameTime*32); evade_vector.z = fixmul(vec_to_player->z, FrameTime*32); break; } // Note: -1 means normal circling about the player. > 0 means fast evasion. if (fast_flag > 0) { fix dot; // Only take evasive action if looking at player. // Evasion speed is scaled by percentage of shields left so wounded robots evade less effectively. dot = vm_vec_dot(vec_to_player, &objp->orient.fvec); if ((dot > robptr->field_of_view[Difficulty_level]) && !(ConsoleObject->flags & PLAYER_FLAGS_CLOAKED)) { fix damage_scale; damage_scale = fixdiv(objp->shields, robptr->strength); if (damage_scale > F1_0) damage_scale = F1_0; // Just in case... else if (damage_scale < 0) damage_scale = 0; // Just in case... vm_vec_scale(&evade_vector, i2f(fast_flag) + damage_scale); } } pptr->velocity.x += evade_vector.x; pptr->velocity.y += evade_vector.y; pptr->velocity.z += evade_vector.z; speed = vm_vec_mag_quick(&pptr->velocity); if (speed > robptr->max_speed[Difficulty_level]) { pptr->velocity.x = (pptr->velocity.x*3)/4; pptr->velocity.y = (pptr->velocity.y*3)/4; pptr->velocity.z = (pptr->velocity.z*3)/4; } } // -------------------------------------------------------------------------------------------------------------------- void move_away_from_player(object *objp, vms_vector *vec_to_player, int attack_type) { fix speed; physics_info *pptr = &objp->mtype.phys_info; robot_info *robptr = &Robot_info[objp->id]; int objref; pptr->velocity.x -= fixmul(vec_to_player->x, FrameTime*16); pptr->velocity.y -= fixmul(vec_to_player->y, FrameTime*16); pptr->velocity.z -= fixmul(vec_to_player->z, FrameTime*16); if (attack_type) { // Get value in 0..3 to choose evasion direction. objref = ((objp-Objects) ^ ((d_tick_count + 3*(objp-Objects)) >> 5)) & 3; switch (objref) { case 0: vm_vec_scale_add2(&pptr->velocity, &objp->orient.uvec, FrameTime << 5); break; case 1: vm_vec_scale_add2(&pptr->velocity, &objp->orient.uvec, -FrameTime << 5); break; case 2: vm_vec_scale_add2(&pptr->velocity, &objp->orient.rvec, FrameTime << 5); break; case 3: vm_vec_scale_add2(&pptr->velocity, &objp->orient.rvec, -FrameTime << 5); break; default: Int3(); // Impossible, bogus value on objref, must be in 0..3 } } speed = vm_vec_mag_quick(&pptr->velocity); if (speed > robptr->max_speed[Difficulty_level]) { pptr->velocity.x = (pptr->velocity.x*3)/4; pptr->velocity.y = (pptr->velocity.y*3)/4; pptr->velocity.z = (pptr->velocity.z*3)/4; } //--old-- fix speed, dot; //--old-- physics_info *pptr = &objp->mtype.phys_info; //--old-- robot_info *robptr = &Robot_info[objp->id]; //--old-- //--old-- // Trying to move away from player. If forward vector much different than velocity vector, //--old-- // bash velocity vector twice as much away from player as usual. //--old-- dot = vm_vec_dot(&pptr->velocity, &objp->orient.fvec); //--old-- if (dot > -3*F1_0/4) { //--old-- // This funny code is supposed to slow down the robot and move his velocity towards his direction //--old-- // more quickly than the general code //--old-- pptr->velocity.x = pptr->velocity.x/2 - fixmul(vec_to_player->x, FrameTime*16); //--old-- pptr->velocity.y = pptr->velocity.y/2 - fixmul(vec_to_player->y, FrameTime*16); //--old-- pptr->velocity.z = pptr->velocity.z/2 - fixmul(vec_to_player->z, FrameTime*16); //--old-- } else { //--old-- pptr->velocity.x -= fixmul(vec_to_player->x, FrameTime*16); //--old-- pptr->velocity.y -= fixmul(vec_to_player->y, FrameTime*16); //--old-- pptr->velocity.z -= fixmul(vec_to_player->z, FrameTime*16); //--old-- } //--old-- //--old-- speed = vm_vec_mag_quick(&pptr->velocity); //--old-- //--old-- if (speed > robptr->max_speed[Difficulty_level]) { //--old-- pptr->velocity.x = (pptr->velocity.x*3)/4; //--old-- pptr->velocity.y = (pptr->velocity.y*3)/4; //--old-- pptr->velocity.z = (pptr->velocity.z*3)/4; //--old-- } } // -------------------------------------------------------------------------------------------------------------------- // Move towards, away_from or around player. // Also deals with evasion. // If the flag evade_only is set, then only allowed to evade, not allowed to move otherwise (must have mode == AIM_STILL). void ai_move_relative_to_player(object *objp, ai_local *ailp, fix dist_to_player, vms_vector *vec_to_player, fix circle_distance, int evade_only) { object *dobjp; robot_info *robptr = &Robot_info[objp->id]; // See if should take avoidance. // New way, green guys don't evade: if ((robptr->attack_type == 0) && (objp->ctype.ai_info.danger_laser_num != -1)) { if (objp->ctype.ai_info.danger_laser_num != -1) { dobjp = &Objects[objp->ctype.ai_info.danger_laser_num]; if ((dobjp->type == OBJ_WEAPON) && (dobjp->signature == objp->ctype.ai_info.danger_laser_signature)) { fix dot, dist_to_laser, field_of_view; vms_vector vec_to_laser, laser_fvec; field_of_view = Robot_info[objp->id].field_of_view[Difficulty_level]; vm_vec_sub(&vec_to_laser, &dobjp->pos, &objp->pos); dist_to_laser = vm_vec_normalize_quick(&vec_to_laser); dot = vm_vec_dot(&vec_to_laser, &objp->orient.fvec); if (dot > field_of_view) { fix laser_robot_dot; vms_vector laser_vec_to_robot; // The laser is seen by the robot, see if it might hit the robot. // Get the laser's direction. If it's a polyobj, it can be gotten cheaply from the orientation matrix. if (dobjp->render_type == RT_POLYOBJ) laser_fvec = dobjp->orient.fvec; else { // Not a polyobj, get velocity and normalize. laser_fvec = dobjp->mtype.phys_info.velocity; //dobjp->orient.fvec; vm_vec_normalize_quick(&laser_fvec); } vm_vec_sub(&laser_vec_to_robot, &objp->pos, &dobjp->pos); vm_vec_normalize_quick(&laser_vec_to_robot); laser_robot_dot = vm_vec_dot(&laser_fvec, &laser_vec_to_robot); if ((laser_robot_dot > F1_0*7/8) && (dist_to_laser < F1_0*80)) { int evade_speed; ai_evaded = 1; evade_speed = Robot_info[objp->id].evade_speed[Difficulty_level]; move_around_player(objp, vec_to_player, evade_speed); } } return; } } // If only allowed to do evade code, then done. // Hmm, perhaps brilliant insight. If want claw-type guys to keep coming, don't return here after evasion. if ((!robptr->attack_type) && evade_only) return; // If we fall out of above, then no object to be avoided. objp->ctype.ai_info.danger_laser_num = -1; // Green guy selects move around/towards/away based on firing time, not distance. if (robptr->attack_type == 1) { if (((ailp->next_fire > robptr->firing_wait[Difficulty_level]/4) && (dist_to_player < F1_0*30)) || Player_is_dead) { // 1/4 of time, move around player, 3/4 of time, move away from player if (d_rand() < 8192) { move_around_player(objp, vec_to_player, -1); } else { move_away_from_player(objp, vec_to_player, 1); } } else { move_towards_player(objp, vec_to_player); } } else { if (dist_to_player < circle_distance) move_away_from_player(objp, vec_to_player, 0); else if (dist_to_player < circle_distance*2) move_around_player(objp, vec_to_player, -1); else move_towards_player(objp, vec_to_player); } } // -------------------------------------------------------------------------------------------------------------------- // Compute a somewhat random, normalized vector. void make_random_vector(vms_vector *vec) { vec->x = (d_rand() - 16384) | 1; // make sure we don't create null vector vec->y = d_rand() - 16384; vec->z = d_rand() - 16384; vm_vec_normalize_quick(vec); } // ------------------------------------------------------------------------------------------------------------------- int Break_on_object = -1; void do_firing_stuff(object *obj, int player_visibility, vms_vector *vec_to_player) { if (player_visibility >= 1) { // Now, if in robot's field of view, lock onto player fix dot = vm_vec_dot(&obj->orient.fvec, vec_to_player); if ((dot >= 7*F1_0/8) || (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) { ai_static *aip = &obj->ctype.ai_info; ai_local *ailp = &Ai_local_info[obj-Objects]; switch (aip->GOAL_STATE) { case AIS_NONE: case AIS_REST: case AIS_SRCH: case AIS_LOCK: aip->GOAL_STATE = AIS_FIRE; if (ailp->player_awareness_type <= PA_NEARBY_ROBOT_FIRED) { ailp->player_awareness_type = PA_NEARBY_ROBOT_FIRED; ailp->player_awareness_time = PLAYER_AWARENESS_INITIAL_TIME; } break; } } else if (dot >= F1_0/2) { ai_static *aip = &obj->ctype.ai_info; switch (aip->GOAL_STATE) { case AIS_NONE: case AIS_REST: case AIS_SRCH: aip->GOAL_STATE = AIS_LOCK; break; } } } } // -------------------------------------------------------------------------------------------------------------------- // If a hiding robot gets bumped or hit, he decides to find another hiding place. void do_ai_robot_hit(object *objp, int type) { if (objp->control_type == CT_AI) { if ((type == PA_WEAPON_ROBOT_COLLISION) || (type == PA_PLAYER_COLLISION)) switch (objp->ctype.ai_info.behavior) { case AIM_HIDE: objp->ctype.ai_info.SUBMODE = AISM_GOHIDE; break; case AIM_STILL: Ai_local_info[objp-Objects].mode = AIM_CHASE_OBJECT; break; } } } #ifndef NDEBUG int Do_ai_flag=1; int Cvv_test=0; int Cvv_last_time[MAX_OBJECTS]; int Gun_point_hack=0; #endif #define CHASE_TIME_LENGTH (F1_0*8) #define DEFAULT_ROBOT_SOUND_VOLUME F1_0 int Robot_sound_volume=DEFAULT_ROBOT_SOUND_VOLUME; // -------------------------------------------------------------------------------------------------------------------- // Note: This function could be optimized. Surely player_is_visible_from_object would benefit from the // information of a normalized vec_to_player. // Return player visibility: // 0 not visible // 1 visible, but robot not looking at player (ie, on an unobstructed vector) // 2 visible and in robot's field of view // -1 player is cloaked // If the player is cloaked, set vec_to_player based on time player cloaked and last uncloaked position. // Updates ailp->previous_visibility if player is not cloaked, in which case the previous visibility is left unchanged // and is copied to player_visibility void compute_vis_and_vec(object *objp, vms_vector *pos, ai_local *ailp, vms_vector *vec_to_player, int *player_visibility, robot_info *robptr, int *flag) { if (!*flag) { if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { fix delta_time, dist; int cloak_index = (objp-Objects) % MAX_AI_CLOAK_INFO; delta_time = GameTime64 - Ai_cloak_info[cloak_index].last_time; if (delta_time > F1_0*2) { vms_vector randvec; Ai_cloak_info[cloak_index].last_time = GameTime64; make_random_vector(&randvec); vm_vec_scale_add2(&Ai_cloak_info[cloak_index].last_position, &randvec, 8*delta_time ); } dist = vm_vec_normalized_dir_quick(vec_to_player, &Ai_cloak_info[cloak_index].last_position, pos); *player_visibility = player_is_visible_from_object(objp, pos, robptr->field_of_view[Difficulty_level], vec_to_player); // *player_visibility = 2; if ((ailp->next_misc_sound_time < GameTime64) && (ailp->next_fire < F1_0) && (dist < F1_0*20)) { ailp->next_misc_sound_time = GameTime64 + (d_rand() + F1_0) * (7 - Difficulty_level) / 1; digi_link_sound_to_pos( robptr->see_sound, objp->segnum, 0, pos, 0 , Robot_sound_volume); } } else { // Compute expensive stuff -- vec_to_player and player_visibility vm_vec_normalized_dir_quick(vec_to_player, &Believed_player_pos, pos); if ((vec_to_player->x == 0) && (vec_to_player->y == 0) && (vec_to_player->z == 0)) { con_printf(CON_DEBUG, "Warning: Player and robot at exactly the same location.\n"); vec_to_player->x = F1_0; } *player_visibility = player_is_visible_from_object(objp, pos, robptr->field_of_view[Difficulty_level], vec_to_player); // This horrible code added by MK in desperation on 12/13/94 to make robots wake up as soon as they // see you without killing frame rate. { ai_static *aip = &objp->ctype.ai_info; if ((*player_visibility == 2) && (ailp->previous_visibility != 2)) if ((aip->GOAL_STATE == AIS_REST) || (aip->CURRENT_STATE == AIS_REST)) { aip->GOAL_STATE = AIS_FIRE; aip->CURRENT_STATE = AIS_FIRE; } } if (!Player_exploded && (ailp->previous_visibility != *player_visibility) && (*player_visibility == 2)) { if (ailp->previous_visibility == 0) { if (ailp->time_player_seen + F1_0/2 < GameTime64) { digi_link_sound_to_pos( robptr->see_sound, objp->segnum, 0, pos, 0 , Robot_sound_volume); ailp->time_player_sound_attacked = GameTime64; ailp->next_misc_sound_time = GameTime64 + F1_0 + d_rand()*4; } } else if (ailp->time_player_sound_attacked + F1_0/4 < GameTime64) { digi_link_sound_to_pos( robptr->attack_sound, objp->segnum, 0, pos, 0 , Robot_sound_volume); ailp->time_player_sound_attacked = GameTime64; } } if ((*player_visibility == 2) && (ailp->next_misc_sound_time < GameTime64)) { ailp->next_misc_sound_time = GameTime64 + (d_rand() + F1_0) * (7 - Difficulty_level) / 2; digi_link_sound_to_pos( robptr->attack_sound, objp->segnum, 0, pos, 0 , Robot_sound_volume); } ailp->previous_visibility = *player_visibility; } *flag = 1; if (*player_visibility) { ailp->time_player_seen = GameTime64; } } } // -------------------------------------------------------------------------------------------------------------------- // Move the object objp to a spot in which it doesn't intersect a wall. // It might mean moving it outside its current segment. void move_object_to_legal_spot(object *objp) { vms_vector original_pos = objp->pos; int i; segment *segp = &Segments[objp->segnum]; for (i=0; ichildren[i]]); vm_vec_sub(&goal_dir, &segment_center, &objp->pos); vm_vec_normalize_quick(&goal_dir); vm_vec_scale(&goal_dir, objp->size); vm_vec_add2(&objp->pos, &goal_dir); if (!object_intersects_wall(objp)) { int new_segnum = find_point_seg(&objp->pos, objp->segnum); if (new_segnum != -1) { obj_relink(objp-Objects, new_segnum); return; } } else objp->pos = original_pos; } } // Int3(); // Darn you John, you done it again! (But contact Mike) con_printf(CON_DEBUG, "Note: Killing robot #%hu because he's badly stuck outside the mine.\n", (unsigned short)(objp-Objects)); apply_damage_to_robot(objp, objp->shields*2, objp-Objects); } // -------------------------------------------------------------------------------------------------------------------- // Move object one object radii from current position towards segment center. // If segment center is nearer than 2 radii, move it to center. void move_towards_segment_center(object *objp) { /* ZICO's change of 20081103: Make move to segment center smoother by using move_towards vector. Bot's should not jump around and maybe even intersect with each other! In case it breaks something what I do not see, yet, old code is still there. */ #if 1 int segnum = objp->segnum; vms_vector vec_to_center, segment_center; compute_segment_center(&segment_center, &Segments[segnum]); vm_vec_normalized_dir_quick(&vec_to_center, &segment_center, &objp->pos); move_towards_vector(objp, &vec_to_center); #else int segnum = objp->segnum; fix dist_to_center; vms_vector segment_center, goal_dir; compute_segment_center(&segment_center, &Segments[segnum]); vm_vec_sub(&goal_dir, &segment_center, &objp->pos); dist_to_center = vm_vec_normalize_quick(&goal_dir); if (dist_to_center < objp->size) { // Center is nearer than the distance we want to move, so move to center. objp->pos = segment_center; if (object_intersects_wall(objp)) { move_object_to_legal_spot(objp); } } else { int new_segnum; // Move one radii towards center. vm_vec_scale(&goal_dir, objp->size); vm_vec_add2(&objp->pos, &goal_dir); new_segnum = find_point_seg(&objp->pos, objp->segnum); if (new_segnum == -1) { objp->pos = segment_center; move_object_to_legal_spot(objp); } } #endif } // ----------------------------------------------------------------------------------------------------------- // Return true if door can be flown through by a suitable type robot. // Only brains and avoid robots can open doors. int ai_door_is_openable(object *objp, segment *segp, int sidenum) { int wall_num; // The mighty console object can open all doors (for purposes of determining paths). if (objp == ConsoleObject) { int wall_num = segp->sides[sidenum].wall_num; if (Walls[wall_num].type == WALL_DOOR) return 1; } if ((objp->id == ROBOT_BRAIN) || (objp->ctype.ai_info.behavior == AIB_RUN_FROM)) { wall_num = segp->sides[sidenum].wall_num; if (wall_num != -1) if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].keys == KEY_NONE) && !(Walls[wall_num].flags & WALL_DOOR_LOCKED)) return 1; } return 0; } //--// ----------------------------------------------------------------------------------------------------------- //--// Return true if object *objp is allowed to open door at wall_num //--int door_openable_by_robot(object *objp, int wall_num) //--{ //-- if (objp->id == ROBOT_BRAIN) //-- if (Walls[wall_num].keys == KEY_NONE) //-- return 1; //-- //-- return 0; //--} // ----------------------------------------------------------------------------------------------------------- // Return side of openable door in segment, if any. If none, return -1. int openable_doors_in_segment(object *objp) { int i; int segnum = objp->segnum; for (i=0; i> 15; while (!(WALL_IS_DOORWAY(segp, sidenum) & WID_FLY_FLAG)) sidenum = (d_rand() * 6) >> 15; segnum = segp->children[sidenum]; return segnum; } // -------------------------------------------------------------------------------------------------------------------- // Return true if placing an object of size size at pos *pos intersects a (player or robot or control center) in segment *segp. int check_object_object_intersection(vms_vector *pos, fix size, segment *segp) { int curobjnum; // If this would intersect with another object (only check those in this segment), then try to move. curobjnum = segp->objects; while (curobjnum != -1) { object *curobjp = &Objects[curobjnum]; if ((curobjp->type == OBJ_PLAYER) || (curobjp->type == OBJ_ROBOT) || (curobjp->type == OBJ_CNTRLCEN)) { if (vm_vec_dist_quick(pos, &curobjp->pos) < size + curobjp->size) return 1; } curobjnum = curobjp->next; } return 0; } #ifndef SHAREWARE // -------------------------------------------------------------------------------------------------------------------- // Return true if object created, else return false. int create_gated_robot( int segnum, int object_id) { int objnum; object *objp; segment *segp = &Segments[segnum]; vms_vector object_pos; robot_info *robptr = &Robot_info[object_id]; int i, count=0; fix objsize = Polygon_models[robptr->model_num].rad; int default_behavior; for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_ROBOT) if (Objects[i].matcen_creator == BOSS_GATE_MATCEN_NUM) count++; if (count > 2*Difficulty_level + 3) { Last_gate_time = GameTime64 - 3*Gate_interval/4; return 0; } compute_segment_center(&object_pos, segp); pick_random_point_in_seg(&object_pos, segp-Segments); // See if legal to place object here. If not, move about in segment and try again. if (check_object_object_intersection(&object_pos, objsize, segp)) { Last_gate_time = GameTime64 - 3*Gate_interval/4; return 0; } objnum = obj_create(OBJ_ROBOT, object_id, segnum, &object_pos, &vmd_identity_matrix, objsize, CT_AI, MT_PHYSICS, RT_POLYOBJ); if ( objnum < 0 ) { Last_gate_time = GameTime64 - 3*Gate_interval/4; return 0; } con_printf(CON_DEBUG, "Gating in object %hu in segment %hu\n", (unsigned short)objnum, (unsigned short)(segp-Segments)); #ifdef NETWORK Net_create_objnums[0] = objnum; // A convenient global to get objnum back to caller for multiplayer #endif objp = &Objects[objnum]; //Set polygon-object-specific data objp->rtype.pobj_info.model_num = robptr->model_num; objp->rtype.pobj_info.subobj_flags = 0; //set Physics info objp->mtype.phys_info.mass = robptr->mass; objp->mtype.phys_info.drag = robptr->drag; objp->mtype.phys_info.flags |= (PF_LEVELLING); objp->shields = robptr->strength; objp->matcen_creator = BOSS_GATE_MATCEN_NUM; // flag this robot as having been created by the boss. default_behavior = AIB_NORMAL; if (object_id == 10) // This is a toaster guy! default_behavior = AIB_RUN_FROM; init_ai_object(objp-Objects, default_behavior, -1 ); // Note, -1 = segment this robot goes to to hide, should probably be something useful object_create_explosion(segnum, &object_pos, i2f(10), VCLIP_MORPHING_ROBOT ); digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, segnum, 0, &object_pos, 0 , F1_0); morph_start(objp); Last_gate_time = GameTime64; Players[Player_num].num_robots_level++; Players[Player_num].num_robots_total++; return 1; } // -------------------------------------------------------------------------------------------------------------------- // Make object objp gate in a robot. // The process of him bringing in a robot takes one second. // Then a robot appears somewhere near the player. // Return true if robot successfully created, else return false int gate_in_robot(int type, int segnum) { if (segnum < 0) segnum = Boss_gate_segs[(d_rand() * Num_boss_gate_segs) >> 15]; Assert((segnum >= 0) && (segnum <= Highest_segment_index)); return create_gated_robot(segnum, type); } #endif // -------------------------------------------------------------------------------------------------------------------- int boss_fits_in_seg(object *boss_objp, int segnum) { vms_vector segcenter; int boss_objnum = boss_objp-Objects; int posnum; compute_segment_center(&segcenter, &Segments[segnum]); for (posnum=0; posnum<9; posnum++) { if (posnum > 0) { vms_vector vertex_pos; Assert((posnum-1 >= 0) && (posnum-1 < 8)); vertex_pos = Vertices[Segments[segnum].verts[posnum-1]]; vm_vec_avg(&boss_objp->pos, &vertex_pos, &segcenter); } else boss_objp->pos = segcenter; obj_relink(boss_objnum, segnum); if (!object_intersects_wall(boss_objp)) return 1; } return 0; } #define QUEUE_SIZE 256 // -------------------------------------------------------------------------------------------------------------------- // Create list of segments boss is allowed to teleport to at segptr. // Set *num_segs. // Boss is allowed to teleport to segments he fits in (calls object_intersects_wall) and // he can reach from his initial position (calls find_connected_distance). // If size_check is set, then only add segment if boss can fit in it, else any segment is legal. void init_boss_segments(short segptr[], int *num_segs, int size_check) { int boss_objnum=-1; int i; *num_segs = 0; #ifdef EDITOR N_selected_segs = 0; #endif // See if there is a boss. If not, quick out. for (i=0; i<=Highest_object_index; i++) if ((Objects[i].type == OBJ_ROBOT) && (Robot_info[Objects[i].id].boss_flag)) boss_objnum = i; // if != 1 then there is more than one boss here. if (boss_objnum != -1) { int original_boss_seg; vms_vector original_boss_pos; object *boss_objp = &Objects[boss_objnum]; int head, tail; int seg_queue[QUEUE_SIZE]; //ALREADY IN RENDER.H byte visited[MAX_SEGMENTS]; fix boss_size_save; boss_size_save = boss_objp->size; boss_objp->size = fixmul((F1_0/4)*3, boss_objp->size); original_boss_seg = boss_objp->segnum; original_boss_pos = boss_objp->pos; head = 0; tail = 0; seg_queue[head++] = original_boss_seg; segptr[(*num_segs)++] = original_boss_seg; #ifdef EDITOR Selected_segs[N_selected_segs++] = original_boss_seg; #endif for (i=0; i<=Highest_segment_index; i++) visited[i] = 0; while (tail != head) { int sidenum; segment *segp = &Segments[seg_queue[tail++]]; tail &= QUEUE_SIZE-1; for (sidenum=0; sidenumchildren[sidenum]] == 0) { seg_queue[head++] = segp->children[sidenum]; visited[segp->children[sidenum]] = 1; head &= QUEUE_SIZE-1; if (head > tail) { if (head == tail + QUEUE_SIZE-1) Int3(); // queue overflow. Make it bigger! } else if (head+QUEUE_SIZE == tail + QUEUE_SIZE-1) Int3(); // queue overflow. Make it bigger! if ((!size_check) || boss_fits_in_seg(boss_objp, segp->children[sidenum])) { segptr[(*num_segs)++] = segp->children[sidenum]; #ifdef EDITOR Selected_segs[N_selected_segs++] = segp->children[sidenum]; #endif if (*num_segs >= MAX_BOSS_TELEPORT_SEGS) { tail = head; sidenum=MAX_SIDES_PER_SEGMENT; break; } } } } } } boss_objp->size = boss_size_save; boss_objp->pos = original_boss_pos; obj_relink(boss_objnum, original_boss_seg); } } // -------------------------------------------------------------------------------------------------------------------- void teleport_boss(object *objp) { int rand_segnum; vms_vector boss_dir; int rand_seg; Assert(Num_boss_teleport_segs > 0); // Pick a random segment from the list of boss-teleportable-to segments. rand_seg = (d_rand() * Num_boss_teleport_segs) >> 15; rand_segnum = Boss_teleport_segs[rand_seg]; Assert((rand_segnum >= 0) && (rand_segnum <= Highest_segment_index)); #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_boss_actions(objp-Objects, 1, rand_seg, 0); #endif #endif compute_segment_center(&objp->pos, &Segments[rand_segnum]); obj_relink(objp-Objects, rand_segnum); Last_teleport_time = GameTime64; // make boss point right at player vm_vec_sub(&boss_dir, &Objects[Players[Player_num].objnum].pos, &objp->pos); vm_vector_2_matrix(&objp->orient, &boss_dir, NULL, NULL); digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, rand_segnum, 0, &objp->pos, 0 , F1_0); digi_kill_sound_linked_to_object( objp-Objects); digi_link_sound_to_object2( SOUND_BOSS_SHARE_SEE, objp-Objects, 1, F1_0, F1_0*512 ); // F1_0*512 means play twice as loud // After a teleport, boss can fire right away. Ai_local_info[objp-Objects].next_fire = 0; } // ---------------------------------------------------------------------- void start_boss_death_sequence(object *objp) { if (Robot_info[objp->id].boss_flag) { Boss_dying = 1; Boss_dying_start_time = GameTime64; } } // ---------------------------------------------------------------------- void do_boss_dying_frame(object *objp) { fix boss_roll_val, temp; boss_roll_val = fixdiv(GameTime64 - Boss_dying_start_time, BOSS_DEATH_DURATION); fix_sincos(fixmul(boss_roll_val, boss_roll_val), &temp, &objp->mtype.phys_info.rotvel.x); fix_sincos(boss_roll_val, &temp, &objp->mtype.phys_info.rotvel.y); fix_sincos(boss_roll_val-F1_0/8, &temp, &objp->mtype.phys_info.rotvel.z); objp->mtype.phys_info.rotvel.x = (GameTime64 - Boss_dying_start_time)/9; objp->mtype.phys_info.rotvel.y = (GameTime64 - Boss_dying_start_time)/5; objp->mtype.phys_info.rotvel.z = (GameTime64 - Boss_dying_start_time)/7; if (Boss_dying_start_time + BOSS_DEATH_DURATION - BOSS_DEATH_SOUND_DURATION < GameTime64) { if (!Boss_dying_sound_playing) { Boss_dying_sound_playing = 1; digi_link_sound_to_object2( SOUND_BOSS_SHARE_DIE, objp-Objects, 0, F1_0*4, F1_0*1024 ); // F1_0*512 means play twice as loud } else if (d_rand() < FrameTime*16) create_small_fireball_on_object(objp, (F1_0 + d_rand()) * 8, 0); } else if (d_rand() < FrameTime*8) create_small_fireball_on_object(objp, (F1_0/2 + d_rand()) * 8, 1); if (Boss_dying_start_time + BOSS_DEATH_DURATION < GameTime64 || GameTime64+(F1_0*2) < Boss_dying_start_time) { Boss_dying_start_time=GameTime64; // make sure following only happens one time! do_controlcen_destroyed_stuff(NULL); explode_object(objp, F1_0/4); digi_link_sound_to_object2(SOUND_BADASS_EXPLOSION, objp-Objects, 0, F2_0, F1_0*512); } } #ifndef SHAREWARE #ifdef NETWORK // -------------------------------------------------------------------------------------------------------------------- // Called for an AI object if it is fairly aware of the player. // awareness_level is in 0..100. Larger numbers indicate greater awareness (eg, 99 if firing at player). // In a given frame, might not get called for an object, or might be called more than once. // The fact that this routine is not called for a given object does not mean that object is not interested in the player. // Objects are moved by physics, so they can move even if not interested in a player. However, if their velocity or // orientation is changing, this routine will be called. // Return value: // 0 this player IS NOT allowed to move this robot. // 1 this player IS allowed to move this robot. int ai_multiplayer_awareness(object *objp, int awareness_level) { int rval=1; #ifndef SHAREWARE if (Game_mode & GM_MULTI) { if (awareness_level == 0) return 0; rval = multi_can_move_robot(objp-Objects, awareness_level); } #endif return rval; } #else #define ai_multiplayer_awareness(a, b) 1 #endif #else #define ai_multiplayer_awareness(a, b) 1 #endif #ifndef NDEBUG fix Prev_boss_shields = -1; #endif // -------------------------------------------------------------------------------------------------------------------- // Do special stuff for a boss. void do_boss_stuff(object *objp) { #ifndef NDEBUG if (objp->shields != Prev_boss_shields) { Prev_boss_shields = objp->shields; } #endif if (!Boss_dying) { if (objp->ctype.ai_info.CLOAKED == 1) { if ((GameTime64 - Boss_cloak_start_time > BOSS_CLOAK_DURATION/3) && (Boss_cloak_end_time - GameTime64 > BOSS_CLOAK_DURATION/3) && (GameTime64 - Last_teleport_time > Boss_teleport_interval)) { if (ai_multiplayer_awareness(objp, 98)) teleport_boss(objp); } else if (Boss_hit_this_frame) { Boss_hit_this_frame = 0; Last_teleport_time -= Boss_teleport_interval/4; } if (GameTime64 > Boss_cloak_end_time) objp->ctype.ai_info.CLOAKED = 0; } else { if ((GameTime64 - Boss_cloak_end_time > Boss_cloak_interval) || Boss_hit_this_frame) { if (ai_multiplayer_awareness(objp, 95)) { Boss_hit_this_frame = 0; Boss_cloak_start_time = GameTime64; Boss_cloak_end_time = GameTime64+Boss_cloak_duration; objp->ctype.ai_info.CLOAKED = 1; #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_boss_actions(objp-Objects, 2, 0, 0); #endif #endif } } } } else do_boss_dying_frame(objp); } #define BOSS_TO_PLAYER_GATE_DISTANCE (F1_0*150) #ifndef SHAREWARE // -------------------------------------------------------------------------------------------------------------------- // Do special stuff for a boss. void do_super_boss_stuff(object *objp, fix dist_to_player, int player_visibility) { #ifdef NETWORK static int eclip_state = 0; #endif do_boss_stuff(objp); // Only master player can cause gating to occur. #ifdef NETWORK if ((Game_mode & GM_MULTI) && !multi_i_am_master()) return; #endif if ((dist_to_player < BOSS_TO_PLAYER_GATE_DISTANCE) || player_visibility || (Game_mode & GM_MULTI)) { if (GameTime64 - Last_gate_time > Gate_interval/2) { restart_effect(ECLIP_NUM_BOSS); #ifndef SHAREWARE #ifdef NETWORK if (eclip_state == 0) { multi_send_boss_actions(objp-Objects, 4, 0, 0); eclip_state = 1; } #endif #endif } else { stop_effect(ECLIP_NUM_BOSS); #ifndef SHAREWARE #ifdef NETWORK if (eclip_state == 1) { multi_send_boss_actions(objp-Objects, 5, 0, 0); eclip_state = 0; } #endif #endif } if (GameTime64 - Last_gate_time > Gate_interval) if (ai_multiplayer_awareness(objp, 99)) { int rtval; int randtype = (d_rand() * MAX_GATE_INDEX) >> 15; Assert(randtype < MAX_GATE_INDEX); randtype = Super_boss_gate_list[randtype]; Assert(randtype < N_robot_types); rtval = gate_in_robot(randtype, -1); #ifndef SHAREWARE #ifdef NETWORK if (rtval && (Game_mode & GM_MULTI)) { multi_send_boss_actions(objp-Objects, 3, randtype, Net_create_objnums[0]); map_objnum_local_to_local(Net_create_objnums[0]); } #endif #endif } } } #endif //int multi_can_move_robot(object *objp, int awareness_level) //{ // return 0; //} #ifndef SHAREWARE void ai_multi_send_robot_position(int objnum, int force) { #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) { if (force != -1) multi_send_robot_position(objnum, 1); else multi_send_robot_position(objnum, 0); } #endif #endif return; } #else #define ai_multi_send_robot_position(a, b) #endif // -------------------------------------------------------------------------------------------------------------------- // Returns true if this object should be allowed to fire at the player. int maybe_ai_do_actual_firing_stuff(object *obj, ai_static *aip) { if (Game_mode & GM_MULTI) if ((aip->GOAL_STATE != AIS_FLIN) && (obj->id != ROBOT_BRAIN)) if (aip->CURRENT_STATE == AIS_FIRE) return 1; return 0; } // -------------------------------------------------------------------------------------------------------------------- void ai_do_actual_firing_stuff(object *obj, ai_static *aip, ai_local *ailp, robot_info *robptr, vms_vector *vec_to_player, fix dist_to_player, vms_vector *gun_point, int player_visibility, int object_animates) { fix dot; if (player_visibility == 2) { // Changed by mk, 01/04/94, onearm would take about 9 seconds until he can fire at you. // if (((!object_animates) || (ailp->achieved_state[aip->CURRENT_GUN] == AIS_FIRE)) && (ailp->next_fire <= 0)) { if (!object_animates || (ailp->next_fire <= 0)) { dot = vm_vec_dot(&obj->orient.fvec, vec_to_player); if (dot >= 7*F1_0/8) { if (aip->CURRENT_GUN < Robot_info[obj->id].n_guns) { if (robptr->attack_type == 1) { if (!Player_exploded && (dist_to_player < obj->size + ConsoleObject->size + F1_0*2)) { // robptr->circle_distance[Difficulty_level] + ConsoleObject->size) { if (!ai_multiplayer_awareness(obj, ROBOT_FIRE_AGITATION-2)) return; do_ai_robot_hit_attack(obj, ConsoleObject, &obj->pos); } else { return; } } else { if ((gun_point->x == 0) && (gun_point->y == 0) && (gun_point->z == 0)) { ; } else { if (!ai_multiplayer_awareness(obj, ROBOT_FIRE_AGITATION)) return; ai_fire_laser_at_player(obj, gun_point); } } // Wants to fire, so should go into chase mode, probably. if ( (aip->behavior != AIB_RUN_FROM) && (aip->behavior != AIB_STILL) && (aip->behavior != AIB_FOLLOW_PATH) && ((ailp->mode == AIM_FOLLOW_PATH) || (ailp->mode == AIM_STILL))) ailp->mode = AIM_CHASE_OBJECT; } aip->GOAL_STATE = AIS_RECO; ailp->goal_state[aip->CURRENT_GUN] = AIS_RECO; // Switch to next gun for next fire. aip->CURRENT_GUN++; if (aip->CURRENT_GUN >= Robot_info[obj->id].n_guns) aip->CURRENT_GUN = 0; } } } else if (Weapon_info[Robot_info[obj->id].weapon_type].homing_flag == 1) { // Robots which fire homing weapons might fire even if they don't have a bead on the player. if (((!object_animates) || (ailp->achieved_state[aip->CURRENT_GUN] == AIS_FIRE)) && (ailp->next_fire <= 0) && (vm_vec_dist_quick(&Hit_pos, &obj->pos) > F1_0*40)) { if (!ai_multiplayer_awareness(obj, ROBOT_FIRE_AGITATION)) return; ai_fire_laser_at_player(obj, gun_point); aip->GOAL_STATE = AIS_RECO; ailp->goal_state[aip->CURRENT_GUN] = AIS_RECO; // Switch to next gun for next fire. aip->CURRENT_GUN++; if (aip->CURRENT_GUN >= Robot_info[obj->id].n_guns) aip->CURRENT_GUN = 0; } else { // Switch to next gun for next fire. aip->CURRENT_GUN++; if (aip->CURRENT_GUN >= Robot_info[obj->id].n_guns) aip->CURRENT_GUN = 0; } } } // -------------------------------------------------------------------------------------------------------------------- void do_ai_frame(object *obj) { int objnum = obj-Objects; ai_static *aip = &obj->ctype.ai_info; ai_local *ailp = &Ai_local_info[objnum]; fix dist_to_player; vms_vector vec_to_player; fix dot; robot_info *robptr; int player_visibility=-1; int obj_ref; int object_animates; int new_goal_state; int visibility_and_vec_computed = 0; int previous_visibility; vms_vector gun_point; vms_vector vis_vec_pos; if (aip->SKIP_AI_COUNT) { aip->SKIP_AI_COUNT--; return; } // Kind of a hack. If a robot is flinching, but it is time for it to fire, unflinch it. // Else, you can turn a big nasty robot into a wimp by firing flares at it. // This also allows the player to see the cool flinch effect for mechs without unbalancing the game. if ((aip->GOAL_STATE == AIS_FLIN) && (ailp->next_fire < 0)) { aip->GOAL_STATE = AIS_FIRE; } #ifndef NDEBUG if ((aip->behavior == AIB_RUN_FROM) && (ailp->mode != AIM_RUN_FROM_OBJECT)) Int3(); // This is peculiar. Behavior is run from, but mode is not. Contact Mike. if (Ai_animation_test) { if (aip->GOAL_STATE == aip->CURRENT_STATE) { aip->GOAL_STATE++; if (aip->GOAL_STATE > AIS_RECO) aip->GOAL_STATE = AIS_REST; } object_animates = do_silly_animation(obj); if (object_animates) ai_frame_animation(obj); return; } if (!Do_ai_flag) return; if (Break_on_object != -1) if ((obj-Objects) == Break_on_object) Int3(); // Contact Mike: This is a debug break #endif Believed_player_pos = Ai_cloak_info[objnum & (MAX_AI_CLOAK_INFO-1)].last_position; // Assert((aip->behavior >= MIN_BEHAVIOR) && (aip->behavior <= MAX_BEHAVIOR)); if (!((aip->behavior >= MIN_BEHAVIOR) && (aip->behavior <= MAX_BEHAVIOR))) { aip->behavior = AIB_NORMAL; } Assert(obj->segnum != -1); Assert(obj->id < N_robot_types); robptr = &Robot_info[obj->id]; Assert(robptr->always_0xabcd == 0xabcd); obj_ref = objnum ^ d_tick_count; // -- if (ailp->wait_time > -F1_0*8) // -- ailp->wait_time -= FrameTime; if (ailp->next_fire > -F1_0*8) ailp->next_fire -= FrameTime; if (ailp->time_since_processed < F1_0*256) ailp->time_since_processed += FrameTime; previous_visibility = ailp->previous_visibility; // Must get this before we toast the master copy! // Deal with cloaking for robots which are cloaked except just before firing. if (robptr->cloak_type == RI_CLOAKED_EXCEPT_FIRING) { if (ailp->next_fire < F1_0/2) aip->CLOAKED = 1; else aip->CLOAKED = 0; } if (!(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) Believed_player_pos = ConsoleObject->pos; dist_to_player = vm_vec_dist_quick(&Believed_player_pos, &obj->pos); // If this robot can fire, compute visibility from gun position. // Don't want to compute visibility twice, as it is expensive. (So is call to calc_gun_point). if ((ailp->next_fire <= 0) && (dist_to_player < F1_0*200) && (robptr->n_guns) && !(robptr->attack_type)) { calc_gun_point(&gun_point, obj, aip->CURRENT_GUN); vis_vec_pos = gun_point; } else { vis_vec_pos = obj->pos; vm_vec_zero(&gun_point); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Occasionally make non-still robots make a path to the player. Based on agitation and distance from player. if ((aip->behavior != AIB_RUN_FROM) && (aip->behavior != AIB_STILL) && !(Game_mode & GM_MULTI)) if (Overall_agitation > 70) { if ((dist_to_player < F1_0*200) && (d_rand() < FrameTime/4)) { if (d_rand() * (Overall_agitation - 40) > F1_0*5) { create_path_to_player(obj, 4 + Overall_agitation/8 + Difficulty_level, 1); // -- show_path_and_other(obj); return; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // If retry count not 0, then add it into consecutive_retries. // If it is 0, cut down consecutive_retries. // This is largely a hack to speed up physics and deal with stupid AI. This is low level // communication between systems of a sort that should not be done. if ((ailp->retry_count) && !(Game_mode & GM_MULTI)) { ailp->consecutive_retries += ailp->retry_count; ailp->retry_count = 0; if (ailp->consecutive_retries > 3) { switch (ailp->mode) { case AIM_CHASE_OBJECT: create_path_to_player(obj, 4 + Overall_agitation/8 + Difficulty_level, 1); break; case AIM_STILL: if (!((aip->behavior == AIB_STILL) || (aip->behavior == AIB_STATION))) // Behavior is still, so don't follow path. attempt_to_resume_path(obj); break; case AIM_FOLLOW_PATH: if (Game_mode & GM_MULTI) ailp->mode = AIM_STILL; else attempt_to_resume_path(obj); break; case AIM_RUN_FROM_OBJECT: move_towards_segment_center(obj); obj->mtype.phys_info.velocity.x = 0; obj->mtype.phys_info.velocity.y = 0; obj->mtype.phys_info.velocity.z = 0; create_n_segment_path(obj, 5, -1); ailp->mode = AIM_RUN_FROM_OBJECT; break; case AIM_HIDE: move_towards_segment_center(obj); obj->mtype.phys_info.velocity.x = 0; obj->mtype.phys_info.velocity.y = 0; obj->mtype.phys_info.velocity.z = 0; if (Overall_agitation > (50 - Difficulty_level*4)) create_path_to_player(obj, 4 + Overall_agitation/8, 1); else { create_n_segment_path(obj, 5, -1); } break; case AIM_OPEN_DOOR: create_n_segment_path_to_door(obj, 5, -1); break; #ifndef NDEBUG case AIM_FOLLOW_PATH_2: Int3(); // Should never happen! break; #endif } ailp->consecutive_retries = 0; } } else ailp->consecutive_retries /= 2; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // If in materialization center, exit if (!(Game_mode & GM_MULTI) && (Segments[obj->segnum].special == SEGMENT_IS_ROBOTMAKER)) { ai_follow_path(obj, 1); // 1 = player is visible, which might be a lie, but it works. return; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Decrease player awareness due to the passage of time. //-----old, faster way from about 11/06/94----- if (ailp->player_awareness_type) { //-----old, faster way from about 11/06/94----- if (ailp->player_awareness_time > 0) { //-----old, faster way from about 11/06/94----- ailp->player_awareness_time -= FrameTime; //-----old, faster way from about 11/06/94----- if (ailp->player_awareness_time <= 0) { //-----old, faster way from about 11/06/94----- ailp->player_awareness_time = F1_0*2; //-----old, faster way from about 11/06/94----- ailp->player_awareness_type--; //-----old, faster way from about 11/06/94----- if (ailp->player_awareness_type < 0) { //-----old, faster way from about 11/06/94----- aip->GOAL_STATE = AIS_REST; //-----old, faster way from about 11/06/94----- ailp->player_awareness_type = 0; //-----old, faster way from about 11/06/94----- } //-----old, faster way from about 11/06/94----- //-----old, faster way from about 11/06/94----- } //-----old, faster way from about 11/06/94----- } else { //-----old, faster way from about 11/06/94----- ailp->player_awareness_type = 0; //-----old, faster way from about 11/06/94----- aip->GOAL_STATE = AIS_REST; //-----old, faster way from about 11/06/94----- } //-----old, faster way from about 11/06/94----- } else //-----old, faster way from about 11/06/94----- aip->GOAL_STATE = AIS_REST; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Decrease player awareness due to the passage of time. if (ailp->player_awareness_type) { if (ailp->player_awareness_time > 0) { ailp->player_awareness_time -= FrameTime; if (ailp->player_awareness_time <= 0) { ailp->player_awareness_time = F1_0*2; //new: 11/05/94 ailp->player_awareness_type--; //new: 11/05/94 } } else { ailp->player_awareness_type--; ailp->player_awareness_time = F1_0*2; //aip->GOAL_STATE = AIS_REST; } } else aip->GOAL_STATE = AIS_REST; //new: 12/13/94 if (Player_is_dead && (ailp->player_awareness_type == 0)) if ((dist_to_player < F1_0*200) && (d_rand() < FrameTime/8)) { if ((aip->behavior != AIB_STILL) && (aip->behavior != AIB_RUN_FROM)) { if (!ai_multiplayer_awareness(obj, 30)) return; ai_multi_send_robot_position(objnum, -1); if (!((ailp->mode == AIM_FOLLOW_PATH) && (aip->cur_path_index < aip->path_length-1))) { if (dist_to_player < F1_0*30) create_n_segment_path(obj, 5, 1); else create_path_to_player(obj, 20, 1); } } } // Make sure that if this guy got hit or bumped, then he's chasing player. if ((ailp->player_awareness_type == PA_WEAPON_ROBOT_COLLISION) || (ailp->player_awareness_type >= PA_PLAYER_COLLISION)) { if ((aip->behavior != AIB_STILL) && (aip->behavior != AIB_FOLLOW_PATH) && (aip->behavior != AIB_RUN_FROM) && (obj->id != ROBOT_BRAIN)) ailp->mode = AIM_CHASE_OBJECT; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if ((aip->GOAL_STATE == AIS_FLIN) && (aip->CURRENT_STATE == AIS_FLIN)) aip->GOAL_STATE = AIS_LOCK; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Note: Should only do these two function calls for objects which animate if ((dist_to_player < F1_0*100)) { // && !(Game_mode & GM_MULTI)) { object_animates = do_silly_animation(obj); if (object_animates) ai_frame_animation(obj); } else { // If Object is supposed to animate, but we don't let it animate due to distance, then // we must change its state, else it will never update. aip->CURRENT_STATE = aip->GOAL_STATE; object_animates = 0; // If we're not doing the animation, then should pretend it doesn't animate. } switch (Robot_info[obj->id].boss_flag) { case 0: break; case 1: if (aip->GOAL_STATE == AIS_FLIN) aip->GOAL_STATE = AIS_FIRE; if (aip->CURRENT_STATE == AIS_FLIN) aip->CURRENT_STATE = AIS_FIRE; dist_to_player /= 4; do_boss_stuff(obj); dist_to_player *= 4; break; #ifndef SHAREWARE case 2: if (aip->GOAL_STATE == AIS_FLIN) aip->GOAL_STATE = AIS_FIRE; if (aip->CURRENT_STATE == AIS_FLIN) aip->CURRENT_STATE = AIS_FIRE; compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); { int pv = player_visibility; fix dtp = dist_to_player/4; // If player cloaked, visibility is screwed up and superboss will gate in robots when not supposed to. if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { pv = 0; dtp = vm_vec_dist_quick(&ConsoleObject->pos, &obj->pos)/4; } do_super_boss_stuff(obj, dtp, pv); } break; #endif default: Int3(); // Bogus boss flag value. } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Time-slice, don't process all the time, purely an efficiency hack. // Guys whose behavior is station and are not at their hide segment get processed anyway. if (ailp->player_awareness_type < PA_WEAPON_ROBOT_COLLISION-1) { // If robot got hit, he gets to attack player always! #ifndef NDEBUG if (Break_on_object != objnum) { // don't time slice if we're interested in this object. #endif if ((dist_to_player > F1_0*250) && (ailp->time_since_processed <= F1_0*2)) return; else if (!((aip->behavior == AIB_STATION) && (ailp->mode == AIM_FOLLOW_PATH) && (aip->hide_segment != obj->segnum))) { if ((dist_to_player > F1_0*150) && (ailp->time_since_processed <= F1_0)) return; else if ((dist_to_player > F1_0*100) && (ailp->time_since_processed <= F1_0/2)) return; } #ifndef NDEBUG } #endif } // Reset time since processed, but skew objects so not everything processed synchronously, else // we get fast frames with the occasional very slow frame. // AI_proc_time = ailp->time_since_processed; ailp->time_since_processed = - ((objnum & 0x03) * FrameTime ) / 2; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Perform special ability switch (obj->id) { case ROBOT_BRAIN: // Robots function nicely if behavior is Station. This means they won't move until they // can see the player, at which time they will start wandering about opening doors. if (ConsoleObject->segnum == obj->segnum) { if (!ai_multiplayer_awareness(obj, 97)) return; compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); move_away_from_player(obj, &vec_to_player, 0); ai_multi_send_robot_position(objnum, -1); } else if (ailp->mode != AIM_STILL) { int r; r = openable_doors_in_segment(obj); if (r != -1) { ailp->mode = AIM_OPEN_DOOR; aip->GOALSIDE = r; } else if (ailp->mode != AIM_FOLLOW_PATH) { if (!ai_multiplayer_awareness(obj, 50)) return; create_n_segment_path_to_door(obj, 8+Difficulty_level, -1); // third parameter is avoid_seg, -1 means avoid nothing. ai_multi_send_robot_position(objnum, -1); } } else { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility) { if (!ai_multiplayer_awareness(obj, 50)) return; create_n_segment_path_to_door(obj, 8+Difficulty_level, -1); // third parameter is avoid_seg, -1 means avoid nothing. ai_multi_send_robot_position(objnum, -1); } } break; default: break; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - switch (ailp->mode) { case AIM_CHASE_OBJECT: { // chasing player, sort of, chase if far, back off if close, circle in between fix circle_distance; circle_distance = robptr->circle_distance[Difficulty_level] + ConsoleObject->size; // Green guy doesn't get his circle distance boosted, else he might never attack. if (robptr->attack_type != 1) circle_distance += (objnum&0xf) * F1_0/2; compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); // @mk, 12/27/94, structure here was strange. Would do both clauses of what are now this if/then/else. Used to be if/then, if/then. if ((player_visibility < 2) && (previous_visibility == 2)) { // this is redundant: mk, 01/15/95: && (ailp->mode == AIM_CHASE_OBJECT)) { if (!ai_multiplayer_awareness(obj, 53)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } create_path_to_player(obj, 8, 1); // -- show_path_and_other(obj); ai_multi_send_robot_position(objnum, -1); } else if ((player_visibility == 0) && (dist_to_player > F1_0*80) && (!(Game_mode & GM_MULTI))) { // If pretty far from the player, player cannot be seen (obstructed) and in chase mode, switch to follow path mode. // This has one desirable benefit of avoiding physics retries. if (aip->behavior == AIB_STATION) { ailp->goal_segment = aip->hide_segment; create_path_to_station(obj, 15); // -- show_path_and_other(obj); } else create_n_segment_path(obj, 5, -1); break; } if ((aip->CURRENT_STATE == AIS_REST) && (aip->GOAL_STATE == AIS_REST)) { if (player_visibility) { if (d_rand() < FrameTime*player_visibility) { if (dist_to_player/256 < d_rand()*player_visibility) { aip->GOAL_STATE = AIS_SRCH; aip->CURRENT_STATE = AIS_SRCH; } } } } if (GameTime64 - ailp->time_player_seen > CHASE_TIME_LENGTH) { if (Game_mode & GM_MULTI) if (!player_visibility && (dist_to_player > F1_0*70)) { ailp->mode = AIM_STILL; return; } if (!ai_multiplayer_awareness(obj, 64)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } create_path_to_player(obj, 10, 1); // -- show_path_and_other(obj); ai_multi_send_robot_position(objnum, -1); } else if ((aip->CURRENT_STATE != AIS_REST) && (aip->GOAL_STATE != AIS_REST)) { if (!ai_multiplayer_awareness(obj, 70)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } ai_move_relative_to_player(obj, ailp, dist_to_player, &vec_to_player, circle_distance, 0); if ((obj_ref & 1) && ((aip->GOAL_STATE == AIS_SRCH) || (aip->GOAL_STATE == AIS_LOCK))) { if (player_visibility) // == 2) ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); else ai_turn_randomly(&vec_to_player, obj, robptr->turn_time[Difficulty_level], previous_visibility); } if (ai_evaded) { ai_multi_send_robot_position(objnum, 1); ai_evaded = 0; } else ai_multi_send_robot_position(objnum, -1); do_firing_stuff(obj, player_visibility, &vec_to_player); } break; } case AIM_RUN_FROM_OBJECT: compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility) { if (ailp->player_awareness_type == 0) ailp->player_awareness_type = PA_WEAPON_ROBOT_COLLISION; } // If in multiplayer, only do if player visible. If not multiplayer, do always. if (!(Game_mode & GM_MULTI) || player_visibility) if (ai_multiplayer_awareness(obj, 75)) { ai_follow_path(obj, player_visibility); ai_multi_send_robot_position(objnum, -1); } if (aip->GOAL_STATE != AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; else if (aip->CURRENT_STATE == AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; // Bad to let run_from robot fire at player because it will cause a war in which it turns towards the // player to fire and then towards its goal to move. // do_firing_stuff(obj, player_visibility, &vec_to_player); // Instead, do this: // (Note, only drop if player is visible. This prevents the bombs from being a giveaway, and // also ensures that the robot is moving while it is dropping. Also means fewer will be dropped.) if ((ailp->next_fire <= 0) && (player_visibility)) { vms_vector fire_vec, fire_pos; if (!ai_multiplayer_awareness(obj, 75)) return; fire_vec = obj->orient.fvec; vm_vec_negate(&fire_vec); vm_vec_add(&fire_pos, &obj->pos, &fire_vec); Laser_create_new_easy( &fire_vec, &fire_pos, obj-Objects, PROXIMITY_ID, 1); ailp->next_fire = F1_0*5; // Drop a proximity bomb every 5 seconds. #ifdef NETWORK #ifndef SHAREWARE if (Game_mode & GM_MULTI) { ai_multi_send_robot_position(obj-Objects, -1); multi_send_robot_fire(obj-Objects, -1, &fire_vec); } #endif #endif } break; case AIM_FOLLOW_PATH: { int anger_level = 65; if (aip->behavior == AIB_STATION) if (Point_segs[aip->hide_index + aip->path_length - 1].segnum == aip->hide_segment) { anger_level = 64; } compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (!ai_multiplayer_awareness(obj, anger_level)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); } return; } ai_follow_path(obj, player_visibility); if (aip->GOAL_STATE != AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; else if (aip->CURRENT_STATE == AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; if ((aip->behavior != AIB_FOLLOW_PATH) && (aip->behavior != AIB_RUN_FROM)) do_firing_stuff(obj, player_visibility, &vec_to_player); if ((player_visibility == 2) && (aip->behavior != AIB_FOLLOW_PATH) && (aip->behavior != AIB_RUN_FROM) && (obj->id != ROBOT_BRAIN)) { if (robptr->attack_type == 0) ailp->mode = AIM_CHASE_OBJECT; } else if ((player_visibility == 0) && (aip->behavior == AIB_NORMAL) && (ailp->mode == AIM_FOLLOW_PATH) && (aip->behavior != AIB_RUN_FROM)) { ailp->mode = AIM_STILL; aip->hide_index = -1; aip->path_length = 0; } ai_multi_send_robot_position(objnum, -1); break; } case AIM_HIDE: if (!ai_multiplayer_awareness(obj, 71)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); } return; } compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); ai_follow_path(obj, player_visibility); if (aip->GOAL_STATE != AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; else if (aip->CURRENT_STATE == AIS_FLIN) aip->GOAL_STATE = AIS_LOCK; ai_multi_send_robot_position(objnum, -1); break; case AIM_STILL: if ((dist_to_player < F1_0*120+Difficulty_level*F1_0*20) || (ailp->player_awareness_type >= PA_WEAPON_ROBOT_COLLISION-1)) { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); // turn towards vector if visible this time or last time, or rand // new! if ((player_visibility) || (previous_visibility) || ((d_rand() > 0x4000) && !(Game_mode & GM_MULTI))) { if (!ai_multiplayer_awareness(obj, 71)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); ai_multi_send_robot_position(objnum, -1); } do_firing_stuff(obj, player_visibility, &vec_to_player); // This is debugging code! Remove it! It's to make the green guy attack without doing other kinds of movement. if (player_visibility) { // Change, MK, 01/03/94 for Multiplayer reasons. If robots can't see you (even with eyes on back of head), then don't do evasion. if (robptr->attack_type == 1) { aip->behavior = AIB_NORMAL; if (!ai_multiplayer_awareness(obj, 80)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } ai_move_relative_to_player(obj, ailp, dist_to_player, &vec_to_player, 0, 0); if (ai_evaded) { ai_multi_send_robot_position(objnum, 1); ai_evaded = 0; } else ai_multi_send_robot_position(objnum, -1); } else { // Robots in hover mode are allowed to evade at half normal speed. if (!ai_multiplayer_awareness(obj, 81)) { if (maybe_ai_do_actual_firing_stuff(obj, aip)) ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } ai_move_relative_to_player(obj, ailp, dist_to_player, &vec_to_player, 0, 1); if (ai_evaded) { ai_multi_send_robot_position(objnum, -1); ai_evaded = 0; } else ai_multi_send_robot_position(objnum, -1); } } else if ((obj->segnum != aip->hide_segment) && (dist_to_player > F1_0*80) && (!(Game_mode & GM_MULTI))) { // If pretty far from the player, player cannot be seen (obstructed) and in chase mode, switch to follow path mode. // This has one desirable benefit of avoiding physics retries. if (aip->behavior == AIB_STATION) { ailp->goal_segment = aip->hide_segment; create_path_to_station(obj, 15); // -- show_path_and_other(obj); } break; } } break; case AIM_OPEN_DOOR: { // trying to open a door. vms_vector center_point, goal_vector; Assert(obj->id == ROBOT_BRAIN); // Make sure this guy is allowed to be in this mode. if (!ai_multiplayer_awareness(obj, 62)) return; compute_center_point_on_side(¢er_point, &Segments[obj->segnum], aip->GOALSIDE); vm_vec_sub(&goal_vector, ¢er_point, &obj->pos); vm_vec_normalize_quick(&goal_vector); ai_turn_towards_vector(&goal_vector, obj, robptr->turn_time[Difficulty_level]); move_towards_vector(obj, &goal_vector); ai_multi_send_robot_position(objnum, -1); break; } default: ailp->mode = AIM_CHASE_OBJECT; break; } // end: switch (ailp->mode) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // If the robot can see you, increase his awareness of you. // This prevents the problem of a robot looking right at you but doing nothing. // Assert(player_visibility != -1); // Means it didn't get initialized! compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility == 2) if (ailp->player_awareness_type == 0) ailp->player_awareness_type = PA_PLAYER_COLLISION; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (!object_animates) { aip->CURRENT_STATE = aip->GOAL_STATE; } Assert(ailp->player_awareness_type <= AIE_MAX); Assert(aip->CURRENT_STATE < AIS_MAX); Assert(aip->GOAL_STATE < AIS_MAX); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (ailp->player_awareness_type) { new_goal_state = Ai_transition_table[ailp->player_awareness_type-1][aip->CURRENT_STATE][aip->GOAL_STATE]; if (ailp->player_awareness_type == PA_WEAPON_ROBOT_COLLISION) { // Decrease awareness, else this robot will flinch every frame. ailp->player_awareness_type--; ailp->player_awareness_time = F1_0*3; } if (new_goal_state == AIS_ERR_) new_goal_state = AIS_REST; if (aip->CURRENT_STATE == AIS_NONE) aip->CURRENT_STATE = AIS_REST; aip->GOAL_STATE = new_goal_state; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // If new state = fire, then set all gun states to fire. if ((aip->GOAL_STATE == AIS_FIRE) ) { int i,num_guns; num_guns = Robot_info[obj->id].n_guns; for (i=0; igoal_state[i] = AIS_FIRE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Hack by mk on 01/04/94, if a guy hasn't animated to the firing state, but his next_fire says ok to fire, bash him there if ((ailp->next_fire < 0) && (aip->GOAL_STATE == AIS_FIRE)) aip->CURRENT_STATE = AIS_FIRE; if ((aip->GOAL_STATE != AIS_FLIN) && (obj->id != ROBOT_BRAIN)) { switch (aip->CURRENT_STATE) { case AIS_NONE: compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); dot = vm_vec_dot(&obj->orient.fvec, &vec_to_player); if (dot >= F1_0/2) if (aip->GOAL_STATE == AIS_REST) aip->GOAL_STATE = AIS_SRCH; break; case AIS_REST: if (aip->GOAL_STATE == AIS_REST) { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if ((ailp->next_fire <= 0) && (player_visibility)) { aip->GOAL_STATE = AIS_FIRE; } } break; case AIS_SRCH: if (!ai_multiplayer_awareness(obj, 60)) return; compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility) { ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); ai_multi_send_robot_position(objnum, -1); } else if (!(Game_mode & GM_MULTI)) ai_turn_randomly(&vec_to_player, obj, robptr->turn_time[Difficulty_level], previous_visibility); break; case AIS_LOCK: compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (!(Game_mode & GM_MULTI) || (player_visibility)) { if (!ai_multiplayer_awareness(obj, 68)) return; if (player_visibility) { ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); ai_multi_send_robot_position(objnum, -1); } else if (!(Game_mode & GM_MULTI)) ai_turn_randomly(&vec_to_player, obj, robptr->turn_time[Difficulty_level], previous_visibility); } break; case AIS_FIRE: compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility) { if (!ai_multiplayer_awareness(obj, (ROBOT_FIRE_AGITATION-1))) { if (Game_mode & GM_MULTI) { ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); return; } } ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); ai_multi_send_robot_position(objnum, -1); } else if (!(Game_mode & GM_MULTI)) { ai_turn_randomly(&vec_to_player, obj, robptr->turn_time[Difficulty_level], previous_visibility); } // Fire at player, if appropriate. ai_do_actual_firing_stuff(obj, aip, ailp, robptr, &vec_to_player, dist_to_player, &gun_point, player_visibility, object_animates); break; case AIS_RECO: if (!(obj_ref & 3)) { compute_vis_and_vec(obj, &vis_vec_pos, ailp, &vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed); if (player_visibility) { if (!ai_multiplayer_awareness(obj, 69)) return; ai_turn_towards_vector(&vec_to_player, obj, robptr->turn_time[Difficulty_level]); ai_multi_send_robot_position(objnum, -1); } else if (!(Game_mode & GM_MULTI)) { ai_turn_randomly(&vec_to_player, obj, robptr->turn_time[Difficulty_level], previous_visibility); } } break; case AIS_FLIN: break; default: aip->GOAL_STATE = AIS_REST; aip->CURRENT_STATE = AIS_REST; break; } } // end of: if (aip->GOAL_STATE != AIS_FLIN) { // Switch to next gun for next fire. if (player_visibility == 0) { aip->CURRENT_GUN++; if (aip->CURRENT_GUN >= Robot_info[obj->id].n_guns) aip->CURRENT_GUN = 0; } } //--mk, 121094 -- // ---------------------------------------------------------------------------------- //--mk, 121094 -- void spin_robot(object *robot, vms_vector *collision_point) //--mk, 121094 -- { //--mk, 121094 -- if (collision_point->x != 3) { //--mk, 121094 -- robot->phys_info.rotvel.x = 0x1235; //--mk, 121094 -- robot->phys_info.rotvel.y = 0x2336; //--mk, 121094 -- robot->phys_info.rotvel.z = 0x3737; //--mk, 121094 -- } //--mk, 121094 -- //--mk, 121094 -- } // ----------------------------------------------------------------------------------- void ai_do_cloak_stuff(void) { int i; for (i=0; ipos; Ai_cloak_info[i].last_time = GameTime64; } // Make work for control centers. Believed_player_pos = Ai_cloak_info[0].last_position; } // ----------------------------------------------------------------------------------- // Returns false if awareness is considered too puny to add, else returns true. int add_awareness_event(object *objp, int type) { // If player cloaked and hit a robot, then increase awareness if ((type == PA_WEAPON_ROBOT_COLLISION) || (type == PA_WEAPON_WALL_COLLISION) || (type == PA_PLAYER_COLLISION)) ai_do_cloak_stuff(); if (Num_awareness_events < MAX_AWARENESS_EVENTS) { if ((type == PA_WEAPON_WALL_COLLISION) || (type == PA_WEAPON_ROBOT_COLLISION)) if (objp->id == VULCAN_ID) if (d_rand() > 3276) return 0; // For vulcan cannon, only about 1/10 actually cause awareness Awareness_events[Num_awareness_events].segnum = objp->segnum; Awareness_events[Num_awareness_events].pos = objp->pos; Awareness_events[Num_awareness_events].type = type; Num_awareness_events++; } else Assert(0); // Hey -- Overflowed Awareness_events, make more or something // This just gets ignored, so you can just continue. return 1; } // ---------------------------------------------------------------------------------- // Robots will become aware of the player based on something that occurred. // The object (probably player or weapon) which created the awareness is objp. void create_awareness_event(object *objp, int type) { if (add_awareness_event(objp, type)) { if (((d_rand() * (type+4)) >> 15) > 4) Overall_agitation++; if (Overall_agitation > OVERALL_AGITATION_MAX) Overall_agitation = OVERALL_AGITATION_MAX; } } sbyte New_awareness[MAX_SEGMENTS]; // ---------------------------------------------------------------------------------- void pae_aux(int segnum, int type, int level) { int j; if (New_awareness[segnum] < type) New_awareness[segnum] = type; // Process children. if (level <= 4) for (j=0; j Ai_local_info[i].player_awareness_type) { Ai_local_info[i].player_awareness_type = New_awareness[Objects[i].segnum]; Ai_local_info[i].player_awareness_time = PLAYER_AWARENESS_INITIAL_TIME; } } #ifndef NDEBUG int Ai_dump_enable = 0; FILE *Ai_dump_file = NULL; char Ai_error_message[128] = ""; // ---------------------------------------------------------------------------------- void dump_ai_objects_all() { #if PARALLAX int objnum; int total=0; time_t time_of_day; time_of_day = time(NULL); if (!Ai_dump_enable) return; if (Ai_dump_file == NULL) Ai_dump_file = fopen("ai.out","a+t"); fprintf(Ai_dump_file, "\nnum: seg distance __mode__ behav. [velx vely velz] (Tick = %i)\n", d_tick_count); fprintf(Ai_dump_file, "Date & Time = %s\n", ctime(&time_of_day)); if (Ai_error_message[0]) fprintf(Ai_dump_file, "Error message: %s\n", Ai_error_message); for (objnum=0; objnum <= Highest_object_index; objnum++) { object *objp = &Objects[objnum]; ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objnum]; fix dist_to_player; dist_to_player = vm_vec_dist(&objp->pos, &ConsoleObject->pos); if (objp->control_type == CT_AI) { fprintf(Ai_dump_file, "%3i: %3i %8.3f %8s %8s [%3i %4i]\n", objnum, objp->segnum, f2fl(dist_to_player), mode_text[ailp->mode], behavior_text[aip->behavior-0x80], aip->hide_index, aip->path_length); if (aip->path_length) total += aip->path_length; } } fprintf(Ai_dump_file, "Total path length = %4i\n", total); #endif } // ---------------------------------------------------------------------------------- void force_dump_ai_objects_all(char *msg) { int tsave; tsave = Ai_dump_enable; Ai_dump_enable = 1; sprintf(Ai_error_message, "%s\n", msg); dump_ai_objects_all(); Ai_error_message[0] = 0; Ai_dump_enable = tsave; } // ---------------------------------------------------------------------------------- void turn_off_ai_dump(void) { if (Ai_dump_file != NULL) fclose(Ai_dump_file); Ai_dump_file = NULL; } #endif // ---------------------------------------------------------------------------------- // Do things which need to get done for all AI objects each frame. // This includes: // Setting player_awareness (a fix, time in seconds which object is aware of player) void do_ai_frame_all(void) { #ifndef NDEBUG dump_ai_objects_all(); #endif set_player_awareness_all(); } // Initializations to be performed for all robots for a new level. void init_robots_for_level(void) { Overall_agitation = 0; } // Following functions convert ai_local/ai_cloak_info to ai_local/ai_cloak_info_rw to be written to/read from Savegames. Convertin back is not done here - reading is done specifically together with swapping (if necessary). These structs differ in terms of timer values (fix/fix64). as we reset GameTime64 for writing so it can fit into fix it's not necessary to increment savegame version. But if we once store something else into object which might be useful after restoring, it might be handy to increment Savegame version and actually store these new infos. void state_ai_local_to_ai_local_rw(ai_local *ail, ai_local_rw *ail_rw) { int i = 0; ail_rw->player_awareness_type = ail->player_awareness_type; ail_rw->retry_count = ail->retry_count; ail_rw->consecutive_retries = ail->consecutive_retries; ail_rw->mode = ail->mode; ail_rw->previous_visibility = ail->previous_visibility; ail_rw->rapidfire_count = ail->rapidfire_count; ail_rw->goal_segment = ail->goal_segment; ail_rw->last_see_time = ail->last_see_time; ail_rw->last_attack_time = ail->last_attack_time; ail_rw->wait_time = ail->wait_time; ail_rw->next_fire = ail->next_fire; ail_rw->player_awareness_time = ail->player_awareness_time; if (ail->time_player_seen - GameTime64 < F1_0*(-18000)) ail_rw->time_player_seen = F1_0*(-18000); else ail_rw->time_player_seen = ail->time_player_seen - GameTime64; if (ail->time_player_sound_attacked - GameTime64 < F1_0*(-18000)) ail_rw->time_player_sound_attacked = F1_0*(-18000); else ail_rw->time_player_sound_attacked = ail->time_player_sound_attacked - GameTime64; ail_rw->time_player_sound_attacked = ail->time_player_sound_attacked; ail_rw->next_misc_sound_time = ail->next_misc_sound_time - GameTime64; ail_rw->time_since_processed = ail->time_since_processed; for (i = 0; i < MAX_SUBMODELS; i++) { ail_rw->goal_angles[i].p = ail->goal_angles[i].p; ail_rw->goal_angles[i].b = ail->goal_angles[i].b; ail_rw->goal_angles[i].h = ail->goal_angles[i].h; ail_rw->delta_angles[i].p = ail->delta_angles[i].p; ail_rw->delta_angles[i].b = ail->delta_angles[i].b; ail_rw->delta_angles[i].h = ail->delta_angles[i].h; ail_rw->goal_state[i] = ail->goal_state[i]; ail_rw->achieved_state[i] = ail->achieved_state[i]; } } void state_ai_cloak_info_to_ai_cloak_info_rw(ai_cloak_info *aic, ai_cloak_info_rw *aic_rw) { if (aic->last_time - GameTime64 < F1_0*(-18000)) aic_rw->last_time = F1_0*(-18000); else aic_rw->last_time = aic->last_time - GameTime64; aic_rw->last_position.x = aic->last_position.x; aic_rw->last_position.x = aic->last_position.y; aic_rw->last_position.z = aic->last_position.z; } int ai_save_state(PHYSFS_file *fp) { int i = 0; fix tmptime32 = 0; PHYSFS_write(fp, &Ai_initialized, sizeof(int), 1); PHYSFS_write(fp, &Overall_agitation, sizeof(int), 1); //PHYSFS_write(fp, Ai_local_info, sizeof(ai_local) * MAX_OBJECTS, 1); for (i = 0; i < MAX_OBJECTS; i++) { ai_local_rw *ail_rw; MALLOC(ail_rw, ai_local_rw, 1); memset(ail_rw, 0, sizeof(ai_local_rw)); state_ai_local_to_ai_local_rw(&Ai_local_info[i], ail_rw); PHYSFS_write(fp, ail_rw, sizeof(ai_local_rw), 1); d_free(ail_rw); } PHYSFS_write(fp, Point_segs, sizeof(point_seg) * MAX_POINT_SEGS, 1); //PHYSFS_write(fp, Ai_cloak_info, sizeof(ai_cloak_info) * MAX_AI_CLOAK_INFO, 1); for (i = 0; i < MAX_AI_CLOAK_INFO; i++) { ai_cloak_info_rw *aic_rw; MALLOC(aic_rw, ai_cloak_info_rw, 1); memset(aic_rw, 0, sizeof(ai_cloak_info_rw)); state_ai_cloak_info_to_ai_cloak_info_rw(&Ai_cloak_info[i], aic_rw); PHYSFS_write(fp, aic_rw, sizeof(ai_cloak_info_rw), 1); d_free(aic_rw); } if (Boss_cloak_start_time - GameTime64 < F1_0*(-18000)) tmptime32 = F1_0*(-18000); else tmptime32 = Boss_cloak_start_time - GameTime64; PHYSFS_write(fp, &tmptime32, sizeof(fix), 1); if (Boss_cloak_end_time - GameTime64 < F1_0*(-18000)) tmptime32 = F1_0*(-18000); else tmptime32 = Boss_cloak_end_time - GameTime64; PHYSFS_write(fp, &tmptime32, sizeof(fix), 1); if (Last_teleport_time - GameTime64 < F1_0*(-18000)) tmptime32 = F1_0*(-18000); else tmptime32 = Last_teleport_time - GameTime64; PHYSFS_write(fp, &tmptime32, sizeof(fix), 1); PHYSFS_write(fp, &Boss_teleport_interval, sizeof(fix), 1); PHYSFS_write(fp, &Boss_cloak_interval, sizeof(fix), 1); PHYSFS_write(fp, &Boss_cloak_duration, sizeof(fix), 1); if (Last_gate_time - GameTime64 < F1_0*(-18000)) tmptime32 = F1_0*(-18000); else tmptime32 = Last_gate_time - GameTime64; PHYSFS_write(fp, &tmptime32, sizeof(fix), 1); PHYSFS_write(fp, &Gate_interval, sizeof(fix), 1); if (Boss_dying_start_time == 0) // if Boss not dead, yet we expect this to be 0, so do not convert! { tmptime32 = 0; } else { if (Boss_dying_start_time - GameTime64 < F1_0*(-18000)) tmptime32 = F1_0*(-18000); else tmptime32 = Boss_dying_start_time - GameTime64; if (tmptime32 == 0) // now if our converted value went 0 we should do something against it tmptime32 = -1; } PHYSFS_write(fp, &tmptime32, sizeof(fix), 1); PHYSFS_write(fp, &Boss_dying, sizeof(int), 1); PHYSFS_write(fp, &Boss_dying_sound_playing, sizeof(int), 1); PHYSFS_write(fp, &Boss_hit_this_frame, sizeof(int), 1); PHYSFS_write(fp, &Boss_been_hit, sizeof(int), 1); return 1; } void ai_local_read_n_swap(ai_local *ail, int n, int swap, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++, ail++) { int j; fix tmptime32 = 0; ail->player_awareness_type = PHYSFSX_readByte(fp); ail->retry_count = PHYSFSX_readByte(fp); ail->consecutive_retries = PHYSFSX_readByte(fp); ail->mode = PHYSFSX_readByte(fp); ail->previous_visibility = PHYSFSX_readByte(fp); ail->rapidfire_count = PHYSFSX_readByte(fp); ail->goal_segment = PHYSFSX_readSXE16(fp, swap); ail->last_see_time = PHYSFSX_readSXE32(fp, swap); ail->last_attack_time = PHYSFSX_readSXE32(fp, swap); ail->wait_time = PHYSFSX_readSXE32(fp, swap); ail->next_fire = PHYSFSX_readSXE32(fp, swap); ail->player_awareness_time = PHYSFSX_readSXE32(fp, swap); tmptime32 = PHYSFSX_readSXE32(fp, swap); ail->time_player_seen = (fix64)tmptime32; tmptime32 = PHYSFSX_readSXE32(fp, swap); ail->time_player_sound_attacked = (fix64)tmptime32; tmptime32 = PHYSFSX_readSXE32(fp, swap); ail->next_misc_sound_time = (fix64)tmptime32; ail->time_since_processed = PHYSFSX_readSXE32(fp, swap); for (j = 0; j < MAX_SUBMODELS; j++) PHYSFSX_readAngleVecX(fp, &ail->goal_angles[j], swap); for (j = 0; j < MAX_SUBMODELS; j++) PHYSFSX_readAngleVecX(fp, &ail->delta_angles[j], swap); for (j = 0; j < MAX_SUBMODELS; j++) ail->goal_state[j] = PHYSFSX_readByte(fp); for (j = 0; j < MAX_SUBMODELS; j++) ail->achieved_state[j] = PHYSFSX_readByte(fp); } } void point_seg_read_n_swap(point_seg *ps, int n, int swap, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++, ps++) { ps->segnum = PHYSFSX_readSXE32(fp, swap); PHYSFSX_readVectorX(fp, &ps->point, swap); } } void ai_cloak_info_read_n_swap(ai_cloak_info *ci, int n, int swap, PHYSFS_file *fp) { int i; fix tmptime32 = 0; for (i = 0; i < n; i++, ci++) { tmptime32 = PHYSFSX_readSXE32(fp, swap); ci->last_time = (fix64)tmptime32; PHYSFSX_readVectorX(fp, &ci->last_position, swap); } } int ai_restore_state(PHYSFS_file *fp, int version, int swap) { (void)version; fix tmptime32 = 0; Ai_initialized = PHYSFSX_readSXE32(fp, swap); Overall_agitation = PHYSFSX_readSXE32(fp, swap); ai_local_read_n_swap(Ai_local_info, MAX_OBJECTS, swap, fp); point_seg_read_n_swap(Point_segs, MAX_POINT_SEGS, swap, fp); ai_cloak_info_read_n_swap(Ai_cloak_info, MAX_AI_CLOAK_INFO, swap, fp); tmptime32 = PHYSFSX_readSXE32(fp, swap); Boss_cloak_start_time = (fix64)tmptime32; tmptime32 = PHYSFSX_readSXE32(fp, swap); Boss_cloak_end_time = (fix64)tmptime32; tmptime32 = PHYSFSX_readSXE32(fp, swap); Last_teleport_time = (fix64)tmptime32; Boss_teleport_interval = PHYSFSX_readSXE32(fp, swap); Boss_cloak_interval = PHYSFSX_readSXE32(fp, swap); Boss_cloak_duration = PHYSFSX_readSXE32(fp, swap); tmptime32 = PHYSFSX_readSXE32(fp, swap); Last_gate_time = (fix64)tmptime32; Gate_interval = PHYSFSX_readSXE32(fp, swap); tmptime32 = PHYSFSX_readSXE32(fp, swap); Boss_dying_start_time = (fix64)tmptime32; Boss_dying = PHYSFSX_readSXE32(fp, swap); Boss_dying_sound_playing = PHYSFSX_readSXE32(fp, swap); Boss_hit_this_frame = PHYSFSX_readSXE32(fp, swap); Boss_been_hit = PHYSFSX_readSXE32(fp, swap); return 1; } dxx-rebirth-0.58.1-d1x/main/ai.h000066400000000000000000000103741217717257200162450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header file for AI system. * */ #ifndef _AI_H #define _AI_H #include "object.h" #define PLAYER_AWARENESS_INITIAL_TIME (3*F1_0) #define MAX_PATH_LENGTH 30 // Maximum length of path in ai path following. #define MAX_DEPTH_TO_SEARCH_FOR_PLAYER 10 #define BOSS_GATE_MATCEN_NUM -1 #define MAX_BOSS_TELEPORT_SEGS 100 #define ROBOT_BRAIN 7 #define ROBOT_BOSS1 17 extern fix64 Boss_cloak_start_time, Boss_cloak_end_time; extern int Boss_hit_this_frame; extern int Num_boss_teleport_segs; extern short Boss_teleport_segs[MAX_BOSS_TELEPORT_SEGS]; extern fix64 Last_teleport_time; extern fix Boss_cloak_duration; extern int Boss_dying; extern ai_local Ai_local_info[MAX_OBJECTS]; extern vms_vector Believed_player_pos; extern void move_towards_segment_center(object *objp); extern int gate_in_robot(int type, int segnum); extern void do_ai_movement(object *objp); extern void ai_move_to_new_segment( object * obj, short newseg, int first_time ); // extern void ai_follow_path( object * obj, short newseg, int first_time ); extern void ai_recover_from_wall_hit(object *obj, int segnum); extern void ai_move_one(object *objp); extern void do_ai_frame(object *objp); extern void init_ai_object(int objnum, int initial_mode, int hide_segment); extern void update_player_awareness(object *objp, fix new_awareness); extern void create_awareness_event(object *objp, int type); // object *objp can create awareness of player, amount based on "type" extern void do_ai_frame_all(void); extern void reset_ai_states(object *objp); extern int create_path_points(object *objp, int start_seg, int end_seg, point_seg *point_segs, short *num_points, int max_depth, int random_flag, int safety_flag, int avoid_seg); extern void create_all_paths(void); extern void create_path_to_station(object *objp, int max_length); extern void ai_follow_path(object *objp, int player_visibility); extern void ai_turn_towards_vector(vms_vector *vec_to_player, object *obj, fix rate); extern void ai_turn_towards_vel_vec(object *objp, fix rate); extern void init_ai_objects(void); extern void do_ai_robot_hit(object *robot, int type); extern void create_n_segment_path(object *objp, int path_length, int avoid_seg); extern void create_n_segment_path_to_door(object *objp, int path_length, int avoid_seg); extern void make_random_vector(vms_vector *vec); extern void init_robots_for_level(void); extern int ai_behavior_to_mode(int behavior); // max_length is maximum depth of path to create. // If -1, use default: MAX_DEPTH_TO_SEARCH_FOR_PLAYER extern void create_path_to_player(object *objp, int max_length, int safety_flag); extern void attempt_to_resume_path(object *objp); // When a robot and a player collide, some robots attack! extern void do_ai_robot_hit_attack(object *robot, object *player, vms_vector *collision_point); extern void ai_open_doors_in_segment(object *robot); extern int ai_door_is_openable(object *objp, segment *segp, int sidenum); extern int player_is_visible_from_object(object *objp, vms_vector *pos, fix field_of_view, vms_vector *vec_to_player); extern void ai_reset_all_paths(void); // Reset all paths. Call at the start of a level. extern int ai_multiplayer_awareness(object *objp, int awareness_level); #ifndef NDEBUG extern void force_dump_ai_objects_all(char *msg); #else #define force_dump_ai_objects_all(msg) #endif extern void start_boss_death_sequence(object *objp); extern void ai_init_boss_for_ship(void); extern int Boss_been_hit; extern fix AI_proc_time; extern int ai_save_state(PHYSFS_file * fp); extern int ai_restore_state(PHYSFS_file *fp, int version, int swap); #endif dxx-rebirth-0.58.1-d1x/main/aipath.c000066400000000000000000001224021217717257200171110ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * AI path forming stuff. * */ #include // for printf() #include // for d_rand() and qsort() #include // for memset() #include "inferno.h" #include "console.h" #include "3d.h" #include "object.h" #include "dxxerror.h" #include "ai.h" #include "robot.h" #include "fvi.h" #include "physics.h" #include "wall.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif #include "player.h" #include "fireball.h" #include "game.h" void validate_all_paths(void); void ai_path_set_orient_and_vel(object *objp, vms_vector *goal_point); void maybe_ai_path_garbage_collect(void); #ifndef NDEBUG int validate_path(int debug_flag, point_seg *psegs, int num_points); #endif #define PARALLAX 0 // If !0, then special debugging for Parallax eyes enabled. // Length in segments of avoidance path #define AVOID_SEG_LENGTH 7 void create_random_xlate(sbyte *xt) { int i; for (i=0; i= 0) && (j < MAX_SIDES_PER_SEGMENT)); temp_byte = xt[j]; xt[j] = xt[i]; xt[i] = temp_byte; } } // ----------------------------------------------------------------------------------------------------------- // Insert the point at the center of the side connecting two segments between the two points. // This is messy because we must insert into the list. The simplest (and not too slow) way to do this is to start // at the end of the list and go backwards. void insert_center_points(point_seg *psegs, short *num_points) { int i, last_point; last_point = *num_points-1; for (i=last_point; i>0; i--) { int connect_side; vms_vector center_point, new_point; psegs[2*i] = psegs[i]; connect_side = find_connect_side(&Segments[psegs[i].segnum], &Segments[psegs[i-1].segnum]); Assert(connect_side != -1); // Impossible! These two segments must be connected, they were created by create_path_points (which was created by mk!) if (connect_side == -1) // Try to blow past the assert, this should at least prevent a hang. connect_side = 0; compute_center_point_on_side(¢er_point, &Segments[psegs[i-1].segnum], connect_side); vm_vec_sub(&new_point, &psegs[i-1].point, ¢er_point); new_point.x /= 16; new_point.y /= 16; new_point.z /= 16; vm_vec_sub(&psegs[2*i-1].point, ¢er_point, &new_point); psegs[2*i-1].segnum = psegs[2*i].segnum; (*num_points)++; } } #ifdef EDITOR int Safety_flag_override = 0; int Random_flag_override = 0; int Ai_path_debug=0; #endif // ----------------------------------------------------------------------------------------------------------- // Create a path from objp->pos to the center of end_seg. // Return a list of (segment_num, point_locations) at psegs // Return number of points in *num_points. // if max_depth == -1, then there is no maximum depth. // If unable to create path, return -1, else return 0. // If random_flag !0, then introduce randomness into path by looking at sides in random order. This means // that a path between two segments won't always be the same, unless it is unique. // If safety_flag is set, then additional points are added to "make sure" that points are reachable. I would // like to say that it ensures that the object can move between the points, but that would require knowing what // the object is (which isn't passed, right?) and making fvi calls (slow, right?). So, consider it the more_or_less_safe_flag. // If end_seg == -2, then end seg will never be found and this routine will drop out due to depth (probably called by create_n_segment_path). int create_path_points(object *objp, int start_seg, int end_seg, point_seg *psegs, short *num_points, int max_depth, int random_flag, int safety_flag, int avoid_seg) { int cur_seg; int sidenum; int qtail = 0, qhead = 0; int i; sbyte visited[MAX_SEGMENTS]; seg_seg seg_queue[MAX_SEGMENTS]; short depth[MAX_SEGMENTS]; int cur_depth; sbyte random_xlate[MAX_SIDES_PER_SEGMENT]; point_seg *original_psegs = psegs; #ifndef NDEBUG point_seg *other_original_psegs = psegs; #endif #ifndef NDEBUG validate_all_paths(); #endif if ((objp->type == OBJ_ROBOT) && (objp->ctype.ai_info.behavior == AIB_RUN_FROM)) { random_flag = 1; avoid_seg = ConsoleObject->segnum; // Int3(); } if (max_depth == -1) max_depth = MAX_PATH_LENGTH; *num_points = 0; // for (i=0; i<=Highest_segment_index; i++) { // visited[i] = 0; // depth[i] = 0; // } memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1)); memset(depth, 0, sizeof(depth[0])*(Highest_segment_index+1)); // If there is a segment we're not allowed to visit, mark it. if (avoid_seg != -1) { Assert(avoid_seg <= Highest_segment_index); if ((start_seg != avoid_seg) && (end_seg != avoid_seg)) { visited[avoid_seg] = 1; depth[avoid_seg] = 0; } } if (random_flag) create_random_xlate(random_xlate); cur_seg = start_seg; visited[cur_seg] = 1; cur_depth = 0; while (cur_seg != end_seg) { segment *segp = &Segments[cur_seg]; for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { int snum = sidenum; if (random_flag) snum = random_xlate[sidenum]; if ((WALL_IS_DOORWAY(segp, snum) & WID_FLY_FLAG) || (ai_door_is_openable(objp, segp, snum))) { int this_seg = segp->children[snum]; if (!visited[this_seg]) { seg_queue[qtail].start = cur_seg; seg_queue[qtail].end = this_seg; visited[this_seg] = 1; depth[qtail++] = cur_depth+1; if (depth[qtail-1] == max_depth) { end_seg = seg_queue[qtail-1].end; goto cpp_done1; } } } } // for (sidenum... if (qtail <= 0) break; if (qhead >= qtail) { // Couldn't get to goal, return a path as far as we got, which probably acceptable to the unparticular caller. end_seg = seg_queue[qtail-1].end; break; } cur_seg = seg_queue[qhead].end; cur_depth = depth[qhead]; qhead++; cpp_done1: ; } // while (cur_seg ... if (qtail > 0) { // Set qtail to the segment which ends at the goal. while (seg_queue[--qtail].end != end_seg) if (qtail < 0) { return -1; } } else qtail = -1; #ifdef EDITOR N_selected_segs = 0; #endif while (qtail >= 0) { int parent_seg, this_seg; this_seg = seg_queue[qtail].end; parent_seg = seg_queue[qtail].start; psegs->segnum = this_seg; compute_segment_center(&psegs->point,&Segments[this_seg]); psegs++; (*num_points)++; #ifdef EDITOR Selected_segs[N_selected_segs++] = this_seg; #endif if (parent_seg == start_seg) break; while (seg_queue[--qtail].end != parent_seg) Assert(qtail >= 0); } psegs->segnum = start_seg; compute_segment_center(&psegs->point,&Segments[start_seg]); psegs++; (*num_points)++; #ifndef NDEBUG validate_path(1, original_psegs, *num_points); #endif // Now, reverse point_segs in place. for (i=0; i< (*num_points)/2; i++) { point_seg temp_point_seg = *(original_psegs + i); *(original_psegs + i) = *(original_psegs + *num_points - i - 1); *(original_psegs + *num_points - i - 1) = temp_point_seg; } #ifndef NDEBUG validate_path(2, original_psegs, *num_points); #endif // Now, if safety_flag set, then insert the point at the center of the side connecting two segments // between the two points. This is messy because we must insert into the list. The simplest (and not too slow) // way to do this is to start at the end of the list and go backwards. if (safety_flag) { if (psegs - Point_segs + *num_points + 2 > MAX_POINT_SEGS) { ai_reset_all_paths(); return -1; } else { insert_center_points(original_psegs, num_points); } } #ifndef NDEBUG validate_path(3, original_psegs, *num_points); validate_path(0, original_psegs, *num_points); Assert(other_original_psegs == original_psegs); #endif return 0; } #ifndef NDEBUG // ------------------------------------------------------------------------------------------------------- // Make sure that there are connections between all segments on path. // Note that if path has been optimized, connections may not be direct, so this function is useless, or worse. // Return true if valid, else return false. int validate_path(int debug_flag, point_seg *psegs, int num_points) { #if PARALLAX int i, curseg; // Trap a common bug elsewhere in aipath. if (psegs > Point_segs_free_ptr) { //Int3(); // Contact Mike: Debug trap for elusive, nasty bug. return 0; } curseg = psegs->segnum; if ((curseg < 0) || (curseg > Highest_segment_index)) { return 0; } if (num_points == 0) return 1; for (i=1; i Highest_segment_index)) { return 0; } if (curseg != nextseg) { for (sidenum=0; sidenumctype.ai_info; //ai_local *ailp = &Ai_local_info[i]; if (objp->control_type == CT_AI) { if ((aip->hide_index != -1) && (aip->path_length > 0)) if (!validate_path(4, &Point_segs[aip->hide_index], aip->path_length)) { //Int3(); // This path is bogus! Who corrupted it! Danger! Danger! // Contact Mike, he caused this mess. //force_dump_ai_objects_all("Error in validate_all_paths"); aip->path_length=0; // This allows people to resume without harm... } } } } #endif } #endif // ------------------------------------------------------------------------------------------------------- // Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to // hide in Ai_local_info[objnum].goal_segment. // Sets objp->ctype.ai_info.hide_index, a pointer into Point_segs, the first point_seg of the path. // objp->ctype.ai_info.path_length, length of path // Point_segs_free_ptr global pointer into Point_segs array void create_path(object *objp) { ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objp-Objects]; int start_seg, end_seg; start_seg = objp->segnum; end_seg = ailp->goal_segment; if (end_seg == -1) create_n_segment_path(objp, 3, -1); if (end_seg == -1) { ; } else { create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, -1, 0, 0, -1); aip->hide_index = Point_segs_free_ptr - Point_segs; aip->cur_path_index = 0; #ifndef NDEBUG validate_path(5, Point_segs_free_ptr, aip->path_length); #endif Point_segs_free_ptr += aip->path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { //Int3(); // Contact Mike: This is curious, though not deadly. /eip++;g //force_dump_ai_objects_all("Error in create_path"); ai_reset_all_paths(); } aip->PATH_DIR = 1; // Initialize to moving forward. aip->SUBMODE = AISM_HIDING; // Pretend we are hiding, so we sit here until bothered. } maybe_ai_path_garbage_collect(); } // ------------------------------------------------------------------------------------------------------- // Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to // hide in Ai_local_info[objnum].goal_segment. // Sets objp->ctype.ai_info.hide_index, a pointer into Point_segs, the first point_seg of the path. // objp->ctype.ai_info.path_length, length of path // Point_segs_free_ptr global pointer into Point_segs array void create_path_to_player(object *objp, int max_length, int safety_flag) { ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objp-Objects]; int start_seg, end_seg; if (max_length == -1) max_length = MAX_DEPTH_TO_SEARCH_FOR_PLAYER; ailp->time_player_seen = GameTime64; // Prevent from resetting path quickly. ailp->goal_segment = ConsoleObject->segnum; start_seg = objp->segnum; end_seg = ailp->goal_segment; if (end_seg == -1) { ; } else { #ifndef NDEBUG point_seg *pseg0 = Point_segs_free_ptr; #endif create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, max_length, 1, safety_flag, -1); aip->hide_index = Point_segs_free_ptr - Point_segs; aip->cur_path_index = 0; #ifndef NDEBUG //Enclosed this Assert in an ifdef, because if NDEBUG isn't defined, //pseg0 doesn't exist! -KRB Assert(Point_segs_free_ptr == pseg0); #endif #ifndef NDEBUG validate_path(6, Point_segs_free_ptr, aip->path_length); #endif Point_segs_free_ptr += aip->path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { //Int3(); // Contact Mike: This is stupid. Should call maybe_ai_garbage_collect before the add. //force_dump_ai_objects_all("Error in create_path_to_player"); ai_reset_all_paths(); return; } // Assert(Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 < MAX_POINT_SEGS); aip->PATH_DIR = 1; // Initialize to moving forward. aip->SUBMODE = AISM_GOHIDE; // This forces immediate movement. ailp->mode = AIM_FOLLOW_PATH; ailp->player_awareness_type = 0; // If robot too aware of player, will set mode to chase } maybe_ai_path_garbage_collect(); } // ------------------------------------------------------------------------------------------------------- // Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to // hide in Ai_local_info[objnum].goal_segment // Sets objp->ctype.ai_info.hide_index, a pointer into Point_segs, the first point_seg of the path. // objp->ctype.ai_info.path_length, length of path // Point_segs_free_ptr global pointer into Point_segs array void create_path_to_station(object *objp, int max_length) { ai_static *aip = &objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objp-Objects]; int start_seg, end_seg; if (max_length == -1) max_length = MAX_DEPTH_TO_SEARCH_FOR_PLAYER; ailp->time_player_seen = GameTime64; // Prevent from resetting path quickly. start_seg = objp->segnum; end_seg = aip->hide_segment; if (end_seg == -1) { ; } else { create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, max_length, 1, 1, -1); aip->hide_index = Point_segs_free_ptr - Point_segs; aip->cur_path_index = 0; #ifndef NDEBUG validate_path(7, Point_segs_free_ptr, aip->path_length); #endif Point_segs_free_ptr += aip->path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { //Int3(); // Contact Mike: Stupid. //force_dump_ai_objects_all("Error in create_path_to_station"); ai_reset_all_paths(); return; } // Assert(Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 < MAX_POINT_SEGS); aip->PATH_DIR = 1; // Initialize to moving forward. // aip->SUBMODE = AISM_GOHIDE; // This forces immediate movement. ailp->mode = AIM_FOLLOW_PATH; ailp->player_awareness_type = 0; } maybe_ai_path_garbage_collect(); } // ------------------------------------------------------------------------------------------------------- // Create a path of length path_length for an object, stuffing info in ai_info field. void create_n_segment_path(object *objp, int path_length, int avoid_seg) { ai_static *aip=&objp->ctype.ai_info; ai_local *ailp = &Ai_local_info[objp-Objects]; if (create_path_points(objp, objp->segnum, -2, Point_segs_free_ptr, &aip->path_length, path_length, 1, 0, avoid_seg) == -1) { //Int3(); // Contact Mike: Considering removing this code. Can I? //force_dump_ai_objects_all("Error in create_n_segment_path"); Point_segs_free_ptr += aip->path_length; while ((create_path_points(objp, objp->segnum, -2, Point_segs_free_ptr, &aip->path_length, --path_length, 1, 0, -1) == -1)) { Assert(path_length); } } aip->hide_index = Point_segs_free_ptr - Point_segs; aip->cur_path_index = 0; #ifndef NDEBUG validate_path(8, Point_segs_free_ptr, aip->path_length); #endif Point_segs_free_ptr += aip->path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { //Int3(); // Contact Mike: This is curious, though not deadly. /eip++;g //force_dump_ai_objects_all("Error in crete_n_segment_path 2"); ai_reset_all_paths(); } aip->PATH_DIR = 1; // Initialize to moving forward. aip->SUBMODE = -1; // Don't know what this means. ailp->mode = AIM_FOLLOW_PATH; maybe_ai_path_garbage_collect(); } // ------------------------------------------------------------------------------------------------------- void create_n_segment_path_to_door(object *objp, int path_length, int avoid_seg) { create_n_segment_path(objp, path_length, avoid_seg); } //--unused-- // ------------------------------------------------------------------------------------------------------- //--unused-- // For all AI objects which have mode HIDE or RUN_FROM_OBJECT, create a path to run to. //--unused-- void create_all_paths(void) //--unused-- { //--unused-- int i; //--unused-- //--unused-- for (i=0; i<=Highest_object_index; i++) { //--unused-- object *objp = &Objects[i]; //--unused-- if (Objects[i].control_type == CT_AI) { //--unused-- ai_static *aip = &objp->ctype.ai_info; //--unused-- if ((aip->behavior == AIB_HIDE) || (aip->behavior == AIB_RUN_FROM) || (aip->behavior == AIB_FOLLOW_PATH)) //--unused-- create_path(&Objects[i]); //--unused-- } //--unused-- } //--unused-- //--unused-- } extern int Connected_segment_distance; // ---------------------------------------------------------------------------------------------------- void move_object_to_goal(object *objp, vms_vector *goal_point, int goal_seg) { ai_static *aip = &objp->ctype.ai_info; int segnum; Assert(objp->segnum != -1); aip->cur_path_index += aip->PATH_DIR; if (aip->cur_path_index <= 0) { if (aip->behavior == AIB_STATION) { create_path_to_station(objp, 15); return; } aip->cur_path_index = 0; aip->PATH_DIR = -aip->PATH_DIR; } else if (aip->cur_path_index >= aip->path_length) { if (aip->behavior == AIB_STATION) { create_path_to_station(objp, 15); return; } aip->cur_path_index = aip->path_length-1; aip->PATH_DIR = -aip->PATH_DIR; } objp->pos = *goal_point; segnum = find_object_seg(objp); if (segnum == -1) { Int3(); // Oops, object is not in any segment. // Contact Mike: This is impossible. // Hack, move object to center of segment it used to be in. compute_segment_center(&objp->pos, &Segments[objp->segnum]); } else obj_relink(objp-Objects, segnum); } // ---------------------------------------------------------------------------------------------------------- // Optimization: If current velocity will take robot near goal, don't change velocity void ai_follow_path(object *objp, int player_visibility) { ai_static *aip = &objp->ctype.ai_info; vms_vector goal_point, new_goal_point; fix dist_to_goal; // robot_info *robptr = &Robot_info[objp->id]; int forced_break, original_dir, original_index; ai_local *ailp = &Ai_local_info[objp-Objects]; fix threshold_distance; if ((aip->hide_index == -1) || (aip->path_length == 0)) { if (ailp->mode == AIM_RUN_FROM_OBJECT) { create_n_segment_path(objp, 5, -1); ailp->mode = AIM_RUN_FROM_OBJECT; } else create_path(objp); } if ((aip->hide_index + aip->path_length > Point_segs_free_ptr - Point_segs) && (aip->path_length>0)) { //Int3(); // Contact Mike: Bad. Path goes into what is believed to be free space. //force_dump_ai_objects_all("Error in ai_follow_path"); ai_reset_all_paths(); } if (aip->path_length < 2) { if (ailp->mode == AIM_RUN_FROM_OBJECT) { if (ConsoleObject->segnum == objp->segnum) create_n_segment_path(objp, AVOID_SEG_LENGTH, -1); // Can't avoid segment player is in, robot is already in it! (That's what the -1 is for) else create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum); ailp->mode = AIM_RUN_FROM_OBJECT; // It gets bashed in create_n_segment_path } else { ailp->mode = AIM_STILL; } return; } Assert((aip->PATH_DIR == -1) || (aip->PATH_DIR == 1)); if ((aip->SUBMODE == AISM_HIDING) && (aip->behavior == AIB_HIDE)) return; goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point; dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos); // If running from player, only run until can't be seen. if (ailp->mode == AIM_RUN_FROM_OBJECT) { if ((player_visibility == 0) && (ailp->player_awareness_type == 0)) { fix vel_scale; vel_scale = F1_0 - FrameTime/2; if (vel_scale < F1_0/2) vel_scale = F1_0/2; vm_vec_scale(&objp->mtype.phys_info.velocity, vel_scale); return; } else { // If player on path (beyond point robot is now at), then create a new path. point_seg *curpsp = &Point_segs[aip->hide_index]; int player_segnum = ConsoleObject->segnum; int i; // This is probably being done every frame, which is wasteful. for (i=aip->cur_path_index; ipath_length; i++) if (curpsp[i].segnum == player_segnum) { if (player_segnum != objp->segnum) create_n_segment_path(objp, AVOID_SEG_LENGTH, player_segnum); else create_n_segment_path(objp, AVOID_SEG_LENGTH, -1); ailp->mode = AIM_RUN_FROM_OBJECT; // It gets bashed in create_n_segment_path break; } if (player_visibility) { ailp->player_awareness_type = 1; ailp->player_awareness_time = F1_0; } } } if (aip->cur_path_index < 0) aip->cur_path_index = 0; else if (aip->cur_path_index >= aip->path_length) { if (ailp->mode == AIM_RUN_FROM_OBJECT) { create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum); ailp->mode = AIM_RUN_FROM_OBJECT; // It gets bashed in create_n_segment_path } else aip->cur_path_index = aip->path_length-1; } goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point; // If near goal, pick another goal point. forced_break = 0; // Gets set for short paths. original_dir = aip->PATH_DIR; original_index = aip->cur_path_index; threshold_distance = fixmul(vm_vec_mag_quick(&objp->mtype.phys_info.velocity), FrameTime)*2 + F1_0*2; while ((dist_to_goal < threshold_distance) && !forced_break) { // Advance to next point on path. aip->cur_path_index += aip->PATH_DIR; // See if next point wraps past end of path (in either direction), and if so, deal with it based on mode. if ((aip->cur_path_index >= aip->path_length) || (aip->cur_path_index < 0)) { // If mode = hiding, then stay here until get bonked or hit by player. if (ailp->mode == AIM_HIDE) { ailp->mode = AIM_STILL; return; // Stay here until bonked or hit by player. } else if (aip->behavior == AIB_STATION) { create_path_to_station(objp, 15); if (aip->hide_segment != Point_segs[aip->hide_index+aip->path_length-1].segnum) { ailp->mode = AIM_STILL; } return; } else if ((ailp->mode == AIM_FOLLOW_PATH) && (aip->behavior != AIB_FOLLOW_PATH)) { create_path_to_player(objp, 10, 1); } else if (ailp->mode == AIM_RUN_FROM_OBJECT) { create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum); ailp->mode = AIM_RUN_FROM_OBJECT; // It gets bashed in create_n_segment_path } else { // Reached end of the line. First see if opposite end point is reachable, and if so, go there. // If not, turn around. int opposite_end_index; vms_vector *opposite_end_point; fvi_info hit_data; int fate; fvi_query fq; // See which end we're nearer and look at the opposite end point. if (abs(aip->cur_path_index - aip->path_length) < aip->cur_path_index) { // Nearer to far end (ie, index not 0), so try to reach 0. opposite_end_index = 0; } else { // Nearer to 0 end, so try to reach far end. opposite_end_index = aip->path_length-1; } opposite_end_point = &Point_segs[aip->hide_index + opposite_end_index].point; fq.p0 = &objp->pos; fq.startseg = objp->segnum; fq.p1 = opposite_end_point; fq.rad = objp->size; fq.thisobjnum = objp-Objects; fq.ignore_obj_list = NULL; fq.flags = 0; //what about trans walls??? fate = find_vector_intersection(&fq,&hit_data); if (fate != HIT_WALL) { // We can be circular! Do it! // Path direction is unchanged. aip->cur_path_index = opposite_end_index; } else { aip->PATH_DIR = -aip->PATH_DIR; } } break; } else { new_goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point; goal_point = new_goal_point; dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos); } // If went all the way around to original point, in same direction, then get out of here! // Cur_index[debug_count] = aip->cur_path_index; // Cur_dir[debug_count] = aip->PATH_DIR; // debug_count++; if ((aip->cur_path_index == original_index) && (aip->PATH_DIR == original_dir)) { create_path_to_player(objp, 3, 1); forced_break = 1; } } // end while // Set velocity (objp->mtype.phys_info.velocity) and orientation (objp->orient) for this object. ai_path_set_orient_and_vel(objp, &goal_point); } typedef struct { short path_start, objnum; } obj_path; int path_index_compare(obj_path *i1, obj_path *i2) { if (i1->path_start < i2->path_start) return -1; else if (i1->path_start == i2->path_start) return 0; else return 1; } // ---------------------------------------------------------------------------------------------------------- // Set orientation matrix and velocity for objp based on its desire to get to a point. void ai_path_set_orient_and_vel(object *objp, vms_vector *goal_point) { vms_vector cur_vel = objp->mtype.phys_info.velocity; vms_vector norm_cur_vel; vms_vector norm_vec_to_goal; vms_vector cur_pos = objp->pos; vms_vector norm_fvec; fix speed_scale; fix dot; robot_info *robptr = &Robot_info[objp->id]; fix max_speed; // If evading player, use highest difficulty level speed, plus something based on diff level max_speed = robptr->max_speed[Difficulty_level]; if (Ai_local_info[objp-Objects].mode == AIM_RUN_FROM_OBJECT) max_speed = max_speed*3/2; vm_vec_sub(&norm_vec_to_goal, goal_point, &cur_pos); vm_vec_normalize_quick(&norm_vec_to_goal); norm_cur_vel = cur_vel; vm_vec_normalize_quick(&norm_cur_vel); norm_fvec = objp->orient.fvec; vm_vec_normalize_quick(&norm_fvec); dot = vm_vec_dot(&norm_vec_to_goal, &norm_fvec); // If very close to facing opposite desired vector, perturb vector if (dot < -15*F1_0/16) { norm_cur_vel = norm_vec_to_goal; } else { norm_cur_vel.x += norm_vec_to_goal.x/2/((float)(F1_0/30)/FrameTime); norm_cur_vel.y += norm_vec_to_goal.y/2/((float)(F1_0/30)/FrameTime); norm_cur_vel.z += norm_vec_to_goal.z/2/((float)(F1_0/30)/FrameTime); } vm_vec_normalize_quick(&norm_cur_vel); // Set speed based on this robot type's maximum allowed speed and how hard it is turning. // How hard it is turning is based on the dot product of (vector to goal) and (current velocity vector) // Note that since 3*F1_0/4 is added to dot product, it is possible for the robot to back up. // Set speed and orientation. if (dot < 0) dot /= -4; speed_scale = fixmul(max_speed, dot); vm_vec_scale(&norm_cur_vel, speed_scale); objp->mtype.phys_info.velocity = norm_cur_vel; if (Ai_local_info[objp-Objects].mode == AIM_RUN_FROM_OBJECT) ai_turn_towards_vector(&norm_vec_to_goal, objp, robptr->turn_time[NDL-1]/2); else ai_turn_towards_vector(&norm_vec_to_goal, objp, robptr->turn_time[Difficulty_level]); } int Last_tick_garbage_collected = 0; // ---------------------------------------------------------------------------------------------------------- // Garbage colledion -- Free all unused records in Point_segs and compress all paths. void ai_path_garbage_collect(void) { int free_path_index = 0; int num_path_objects = 0; int objnum; int objind; obj_path object_list[MAX_OBJECTS]; #ifndef NDEBUG force_dump_ai_objects_all("***** Start ai_path_garbage_collect *****"); #endif Last_tick_garbage_collected = d_tick_count; #ifndef NDEBUG validate_all_paths(); #endif // Create a list of objects which have paths of length 1 or more. for (objnum=0; objnum <= Highest_object_index; objnum++) { object *objp = &Objects[objnum]; if ((objp->type == OBJ_ROBOT) && (objp->control_type == CT_AI)) { ai_static *aip = &objp->ctype.ai_info; if (aip->path_length) { object_list[num_path_objects].path_start = aip->hide_index; object_list[num_path_objects++].objnum = objnum; } } } qsort(object_list, num_path_objects, sizeof(object_list[0]), (int (*)(const void *, const void *))path_index_compare); for (objind=0; objind < num_path_objects; objind++) { object *objp; ai_static *aip; int i; int old_index; objnum = object_list[objind].objnum; objp = &Objects[objnum]; aip = &objp->ctype.ai_info; old_index = aip->hide_index; aip->hide_index = free_path_index; for (i=0; ipath_length; i++) Point_segs[free_path_index++] = Point_segs[old_index++]; } Point_segs_free_ptr = &Point_segs[free_path_index]; #ifndef NDEBUG { int i; force_dump_ai_objects_all("***** Finish ai_path_garbage_collect *****"); for (i=0; i<=Highest_object_index; i++) { ai_static *aip = &Objects[i].ctype.ai_info; if ((Objects[i].type == OBJ_ROBOT) && (Objects[i].control_type == CT_AI)) if ((aip->hide_index + aip->path_length > Point_segs_free_ptr - Point_segs) && (aip->path_length>0)) Int3(); // Contact Mike: Debug trap for nasty, elusive bug. } validate_all_paths(); } #endif } // ----------------------------------------------------------------------------- // Do garbage collection if not been done for awhile, or things getting really critical. void maybe_ai_path_garbage_collect(void) { if (Point_segs_free_ptr - Point_segs > MAX_POINT_SEGS - MAX_PATH_LENGTH) { if (Last_tick_garbage_collected+1 >= d_tick_count) { // This is kind of bad. Garbage collected last frame or this frame. // Just destroy all paths. Too bad for the robots. They are memory wasteful. ai_reset_all_paths(); } else { // We are really close to full, but didn't just garbage collect, so maybe this is recoverable. ai_path_garbage_collect(); } } else if (Point_segs_free_ptr - Point_segs > 3*MAX_POINT_SEGS/4) { if (Last_tick_garbage_collected + 16 < d_tick_count) { ai_path_garbage_collect(); } } else if (Point_segs_free_ptr - Point_segs > MAX_POINT_SEGS/2) { if (Last_tick_garbage_collected + 256 < d_tick_count) { ai_path_garbage_collect(); } } } // ----------------------------------------------------------------------------- // Reset all paths. Do garbage collection. // Should be called at the start of each level. void ai_reset_all_paths(void) { int i; for (i=0; i<=Highest_object_index; i++) if (Objects[i].control_type == CT_AI) { Objects[i].ctype.ai_info.hide_index = -1; Objects[i].ctype.ai_info.path_length = 0; } ai_path_garbage_collect(); } // --------------------------------------------------------------------------------------------------------- // Probably called because a robot bashed a wall, getting a bunch of retries. // Try to resume path. void attempt_to_resume_path(object *objp) { ai_static *aip = &objp->ctype.ai_info; int new_path_index; if (aip->behavior == AIB_STATION) if (d_rand() > 8192) { ai_local *ailp = &Ai_local_info[objp-Objects]; aip->hide_segment = objp->segnum; ailp->mode = AIM_STILL; } new_path_index = aip->cur_path_index - aip->PATH_DIR; if ((new_path_index >= 0) && (new_path_index < aip->path_length)) { aip->cur_path_index = new_path_index; } else { // At end of line and have nowhere to go. move_towards_segment_center(objp); create_path_to_station(objp, 15); } } // ---------------------------------------------------------------------------------------------------------- // DEBUG FUNCTIONS FOLLOW // ---------------------------------------------------------------------------------------------------------- #ifdef EDITOR int Test_size = 1000; void test_create_path_many(void) { point_seg point_segs[200]; short num_points; int i; for (i=0; i Anchor_distance) //--anchor-- create_new_anchor(segnum); //--anchor-- } //--anchor-- } //--anchor-- //--anchor-- // Set selected segs. //--anchor-- for (i=0; imtype.phys_info.velocity; vms_vector norm_cur_vel; vms_vector norm_vec_to_goal; vms_vector cur_pos = objp->pos; vms_vector norm_fvec; fix speed_scale; fix dot; fix max_speed; max_speed = F1_0*50; vm_vec_sub(&norm_vec_to_goal, goal_point, &cur_pos); vm_vec_normalize_quick(&norm_vec_to_goal); norm_cur_vel = cur_vel; vm_vec_normalize_quick(&norm_cur_vel); norm_fvec = objp->orient.fvec; vm_vec_normalize_quick(&norm_fvec); dot = vm_vec_dot(&norm_vec_to_goal, &norm_fvec); // If very close to facing opposite desired vector, perturb vector if (dot < -15*F1_0/16) { norm_cur_vel = norm_vec_to_goal; } else { norm_cur_vel.x += norm_vec_to_goal.x/2/((float)(F1_0/30)/FrameTime); norm_cur_vel.y += norm_vec_to_goal.y/2/((float)(F1_0/30)/FrameTime); norm_cur_vel.z += norm_vec_to_goal.z/2/((float)(F1_0/30)/FrameTime); } vm_vec_normalize_quick(&norm_cur_vel); // Set speed based on this robot type's maximum allowed speed and how hard it is turning. // How hard it is turning is based on the dot product of (vector to goal) and (current velocity vector) // Note that since 3*F1_0/4 is added to dot product, it is possible for the robot to back up. // Set speed and orientation. if (dot < 0) dot /= 4; speed_scale = fixmul(max_speed, dot); vm_vec_scale(&norm_cur_vel, speed_scale); objp->mtype.phys_info.velocity = norm_cur_vel; ai_turn_towards_vector(&norm_vec_to_goal, objp, F1_0); } // ---------------------------------------------------------------------------------------------------------- // Optimization: If current velocity will take robot near goal, don't change velocity void player_follow_path(object *objp) { vms_vector goal_point; fix dist_to_goal; int count, forced_break, original_index; int goal_seg; fix threshold_distance; if (!Player_following_path_flag) return; if (Player_hide_index == -1) return; if (Player_path_length < 2) return; goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point; goal_seg = Point_segs[Player_hide_index + Player_cur_path_index].segnum; Assert((goal_seg >= 0) && (goal_seg <= Highest_segment_index)); (void)goal_seg; dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos); if (Player_cur_path_index < 0) Player_cur_path_index = 0; else if (Player_cur_path_index >= Player_path_length) Player_cur_path_index = Player_path_length-1; goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point; count=0; // If near goal, pick another goal point. forced_break = 0; // Gets set for short paths. //original_dir = 1; original_index = Player_cur_path_index; threshold_distance = fixmul(vm_vec_mag_quick(&objp->mtype.phys_info.velocity), FrameTime)*2 + F1_0*2; while ((dist_to_goal < threshold_distance) && !forced_break) { // ----- Debug stuff ----- if (count++ > 20) { break; } // Advance to next point on path. Player_cur_path_index += 1; // See if next point wraps past end of path (in either direction), and if so, deal with it based on mode. if ((Player_cur_path_index >= Player_path_length) || (Player_cur_path_index < 0)) { Player_following_path_flag = 0; forced_break = 1; } // If went all the way around to original point, in same direction, then get out of here! if (Player_cur_path_index == original_index) { Player_following_path_flag = 0; forced_break = 1; } goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point; dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos); } // end while // Set velocity (objp->mtype.phys_info.velocity) and orientation (objp->orient) for this object. player_path_set_orient_and_vel(objp, &goal_point); } // ------------------------------------------------------------------------------------------------------------------ // Create path for player from current segment to goal segment. void create_player_path_to_segment(int segnum) { object *objp = ConsoleObject; Player_path_length=0; Player_hide_index=-1; Player_cur_path_index=0; Player_following_path_flag=0; if (create_path_points(objp, objp->segnum, segnum, Point_segs_free_ptr, &Player_path_length, 100, 0, 0, -1) == -1) con_printf(CON_DEBUG,"Unable to form path of length %i for myself\n", 100); Player_following_path_flag = 1; Player_hide_index = Point_segs_free_ptr - Point_segs; Player_cur_path_index = 0; Point_segs_free_ptr += Player_path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { //Int3(); // Contact Mike: This is curious, though not deadly. /eip++;g ai_reset_all_paths(); } } int Player_goal_segment = -1; void check_create_player_path(void) { if (Player_goal_segment != -1) create_player_path_to_segment(Player_goal_segment); Player_goal_segment = -1; } #endif // ---------------------------------------------------------------------------------------------------------- // DEBUG FUNCTIONS ENDED // ---------------------------------------------------------------------------------------------------------- dxx-rebirth-0.58.1-d1x/main/aistruct.h000066400000000000000000000237351217717257200175170ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Structs and constants for AI system. * object.h depends on this. * ai.h depends on object.h. * Get it? * */ #ifndef _AISTRUCT_H #define _AISTRUCT_H #include "inferno.h" #include "polyobj.h" #define GREEN_GUY 1 #define MAX_SEGMENTS_PER_PATH 20 #define PA_WEAPON_WALL_COLLISION 2 // Level of robot awareness after player weapon hits nearby wall //#define PA_PLAYER_VISIBLE 2 // Level of robot awareness if robot is looking towards player, and player not hidden #define PA_NEARBY_ROBOT_FIRED 1 // Level of robot awareness after nearby robot fires a weapon #define PA_PLAYER_COLLISION 3 // Level of robot awareness after player bumps into robot #define PA_WEAPON_ROBOT_COLLISION 4 // Level of robot awareness after player weapon hits nearby robot //#define PAE_WEAPON_HIT_WALL 1 // weapon hit wall, create player awareness //#define PAE_WEAPON_HIT_ROBOT 2 // weapon hit wall, create player awareness // Constants indicating currently moving forward or backward through path. // Note that you can add aip->direction to aip_path_index to get next segment on path. #define AI_DIR_FORWARD 1 #define AI_DIR_BACKWARD (-AI_DIR_FORWARD) // Behaviors #define AIB_STILL 0x80 #define AIB_NORMAL 0x81 #define AIB_HIDE 0x82 #define AIB_RUN_FROM 0x83 #define AIB_FOLLOW_PATH 0x84 #define AIB_STATION 0x85 #define MIN_BEHAVIOR 0x80 #define MAX_BEHAVIOR 0x85 // Modes #define AIM_STILL 0 #define AIM_WANDER 1 #define AIM_FOLLOW_PATH 2 #define AIM_CHASE_OBJECT 3 #define AIM_RUN_FROM_OBJECT 4 #define AIM_HIDE 5 #define AIM_FOLLOW_PATH_2 6 #define AIM_OPEN_DOOR 7 #define AISM_GOHIDE 0 #define AISM_HIDING 1 #define AI_MAX_STATE 7 #define AI_MAX_EVENT 4 #define AIS_NONE 0 #define AIS_REST 1 #define AIS_SRCH 2 #define AIS_LOCK 3 #define AIS_FLIN 4 #define AIS_FIRE 5 #define AIS_RECO 6 #define AIS_ERR_ 7 #define AIE_FIRE 0 #define AIE_HITT 1 #define AIE_COLL 2 #define AIE_HURT 3 //typedef struct opath { // byte path_index; // current index of path // byte path_direction; // current path direction // byte path_length; // length of current path // byte nothing; // short path[MAX_SEGMENTS_PER_PATH]; // short always_0xabc; // If this is ever not 0xabc, then someone overwrote //} opath; // //typedef struct oai_state { // short mode; // // short counter; // kind of a hack, frame countdown until switch modes // opath paths[2]; // vms_vector movement_vector; // movement vector for one second //} oai_state; // Constants defining meaning of flags in ai_state #define MAX_AI_FLAGS 11 // This MUST cause word (4 bytes) alignment in ai_static, allowing for one byte mode #define CURRENT_GUN flags[0] // This is the last gun the object fired from #define CURRENT_STATE flags[1] // current behavioral state #define GOAL_STATE flags[2] // goal state #define PATH_DIR flags[3] // direction traveling path, 1 = forward, -1 = backward, other = error! #define SUBMODE flags[4] // submode, eg AISM_HIDING if mode == AIM_HIDE #define GOALSIDE flags[5] // for guys who open doors, this is the side they are going after. #define CLOAKED flags[6] // Cloaked now. #define SKIP_AI_COUNT flags[7] // Skip AI this frame, but decrement in do_ai_frame. #define REMOTE_OWNER flags[8] // Who is controlling this remote AI object (multiplayer use only) #define REMOTE_SLOT_NUM flags[9] // What slot # is this robot in for remote control purposes (multiplayer use only) #define MULTI_ANGER flags[10] // How angry is a robot in multiplayer mode // This is the stuff that is permanent for an AI object. typedef struct ai_static { ubyte behavior; // sbyte flags[MAX_AI_FLAGS]; // various flags, meaning defined by constants short hide_segment; // Segment to go to for hiding. short hide_index; // Index in Path_seg_points short path_length; // Length of hide path. short cur_path_index; // Current index in path. short follow_path_start_seg; // Start segment for robot which follows path. short follow_path_end_seg; // End segment for robot which follows path. int danger_laser_signature; short danger_laser_num; } __pack__ ai_static; // Rather temporal AI stuff. typedef struct ai_local { // These used to be bytes, changed to ints so I could set watchpoints on them. sbyte player_awareness_type; // type of awareness of player sbyte retry_count; // number of retries in physics last time this object got moved. sbyte consecutive_retries; // number of retries in consecutive frames (ie, without a retry_count of 0) sbyte mode; // current mode within behavior sbyte previous_visibility; // Visibility of player last time we checked. sbyte rapidfire_count; // number of shots fired rapidly short goal_segment; // goal segment for current path fix last_see_time, last_attack_time; // For sound effects, time at which player last seen, attacked fix wait_time; // time in seconds until something happens, mode dependent fix next_fire; // time in seconds until can fire again fix player_awareness_time; // time in seconds robot will be aware of player, 0 means not aware of player fix64 time_player_seen; // absolute time in seconds at which player was last seen, might cause to go into follow_path mode fix64 time_player_sound_attacked; // absolute time in seconds at which player was last seen with visibility of 2. fix64 next_misc_sound_time; // absolute time in seconds at which this robot last made an angry or lurking sound. fix time_since_processed; // time since this robot last processed in do_ai_frame vms_angvec goal_angles[MAX_SUBMODELS]; // angles for each subobject vms_angvec delta_angles[MAX_SUBMODELS]; // angles for each subobject sbyte goal_state[MAX_SUBMODELS]; // Goal state for this sub-object sbyte achieved_state[MAX_SUBMODELS]; // Last achieved state } ai_local; // Same as above but structure Savegames expect typedef struct ai_local_rw { // These used to be bytes, changed to ints so I could set watchpoints on them. sbyte player_awareness_type; // type of awareness of player sbyte retry_count; // number of retries in physics last time this object got moved. sbyte consecutive_retries; // number of retries in consecutive frames (ie, without a retry_count of 0) sbyte mode; // current mode within behavior sbyte previous_visibility; // Visibility of player last time we checked. sbyte rapidfire_count; // number of shots fired rapidly short goal_segment; // goal segment for current path fix last_see_time, last_attack_time; // For sound effects, time at which player last seen, attacked fix wait_time; // time in seconds until something happens, mode dependent fix next_fire; // time in seconds until can fire again fix player_awareness_time; // time in seconds robot will be aware of player, 0 means not aware of player fix time_player_seen; // absolute time in seconds at which player was last seen, might cause to go into follow_path mode fix time_player_sound_attacked; // absolute time in seconds at which player was last seen with visibility of 2. fix next_misc_sound_time; // absolute time in seconds at which this robot last made an angry or lurking sound. fix time_since_processed; // time since this robot last processed in do_ai_frame vms_angvec goal_angles[MAX_SUBMODELS]; // angles for each subobject vms_angvec delta_angles[MAX_SUBMODELS]; // angles for each subobject sbyte goal_state[MAX_SUBMODELS]; // Goal state for this sub-object sbyte achieved_state[MAX_SUBMODELS]; // Last achieved state } ai_local_rw; typedef struct { fix64 last_time; vms_vector last_position; } ai_cloak_info; // Same as above but structure Savegames expect typedef struct { fix last_time; vms_vector last_position; } ai_cloak_info_rw; typedef struct { int segnum; vms_vector point; } point_seg; typedef struct { short start, end; } seg_seg; #define MAX_POINT_SEGS 2500 extern point_seg Point_segs[MAX_POINT_SEGS]; extern point_seg *Point_segs_free_ptr; extern int Overall_agitation; // These are the information for a robot describing the location of the player last time he wasn't cloaked, // and the time at which he was uncloaked. We should store this for each robot, but that's memory expensive. //extern fix Last_uncloaked_time; //extern vms_vector Last_uncloaked_position; extern void ai_do_cloak_stuff(void); #endif dxx-rebirth-0.58.1-d1x/main/automap.c000066400000000000000000000772511217717257200173240ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for displaying the auto-map. * */ #include #include #include #ifdef OGL #include "ogl_init.h" #endif #include "dxxerror.h" #include "3d.h" #include "inferno.h" #include "u_mem.h" #include "render.h" #include "object.h" #include "vclip.h" #include "game.h" #include "polyobj.h" #include "sounds.h" #include "player.h" #include "bm.h" #include "key.h" #include "newmenu.h" #include "menu.h" #include "screens.h" #include "textures.h" #include "mouse.h" #include "timer.h" #include "segpoint.h" #include "joy.h" #include "iff.h" #include "pcx.h" #include "palette.h" #include "wall.h" #include "hostage.h" #include "fuelcen.h" #include "gameseq.h" #include "gamefont.h" #ifdef NETWORK #include "multi.h" #endif #include "kconfig.h" #include "endlevel.h" #include "text.h" #include "gauges.h" #include "powerup.h" #include "switch.h" #include "automap.h" #include "cntrlcen.h" #include "timer.h" #include "config.h" #include "rbaudio.h" #include "window.h" #include "playsave.h" #include "args.h" #define LEAVE_TIME 0x4000 #define EF_USED 1 // This edge is used #define EF_DEFINING 2 // A structure defining edge that should always draw. #define EF_FRONTIER 4 // An edge between the known and the unknown. #define EF_SECRET 8 // An edge that is part of a secret wall. #define EF_GRATE 16 // A grate... draw it all the time. #define EF_NO_FADE 32 // An edge that doesn't fade with distance #define EF_TOO_FAR 64 // An edge that is too far away typedef struct Edge_info { int verts[2]; // 8 bytes ubyte sides[4]; // 4 bytes int segnum[4]; // 16 bytes // This might not need to be stored... If you can access the normals of a side. ubyte flags; // 1 bytes // See the EF_??? defines above. ubyte color; // 1 bytes ubyte num_faces; // 1 bytes // 31 bytes... } Edge_info; typedef struct automap { fix64 entry_time; fix64 t1, t2; int leave_mode; int pause_game; vms_angvec tangles; ushort old_wiggle; // keep 4 byte aligned int max_segments_away; int segment_limit; // Edge list variables int num_edges; int max_edges; //set each frame int highest_edge_index; Edge_info *edges; int *drawingListBright; // Screen canvas variables grs_canvas automap_view; grs_bitmap automap_background; // Rendering variables fix zoom; vms_vector view_target; vms_vector view_position; fix farthest_dist; vms_matrix viewMatrix; fix viewDist; int wall_normal_color; int wall_door_color; int wall_door_blue; int wall_door_gold; int wall_door_red; int wall_revealed_color; int hostage_color; int font_color_20; int green_31; int white_63; int blue_48; int red_48; control_info controls; } automap; #define MAX_EDGES_FROM_VERTS(v) ((v)*4) #define MAX_EDGES 6000 // Determined by loading all the levels by John & Mike, Feb 9, 1995 #define K_WALL_NORMAL_COLOR BM_XRGB(29, 29, 29 ) #define K_WALL_DOOR_COLOR BM_XRGB(5, 27, 5 ) #define K_WALL_DOOR_BLUE BM_XRGB(0, 0, 31) #define K_WALL_DOOR_GOLD BM_XRGB(31, 31, 0) #define K_WALL_DOOR_RED BM_XRGB(31, 0, 0) #define K_HOSTAGE_COLOR BM_XRGB(0, 31, 0 ) #define K_FONT_COLOR_20 BM_XRGB(20, 20, 20 ) #define K_GREEN_31 BM_XRGB(0, 31, 0) int Automap_active = 0; void init_automap_colors(automap *am) { am->wall_normal_color = K_WALL_NORMAL_COLOR; am->wall_door_color = K_WALL_DOOR_COLOR; am->wall_door_blue = K_WALL_DOOR_BLUE; am->wall_door_gold = K_WALL_DOOR_GOLD; am->wall_door_red = K_WALL_DOOR_RED; am->hostage_color = K_HOSTAGE_COLOR; am->font_color_20 = K_FONT_COLOR_20; am->green_31 = K_GREEN_31; am->white_63 = gr_find_closest_color_current(63,63,63); am->blue_48 = gr_find_closest_color_current(0,0,48); am->red_48 = gr_find_closest_color_current(48,0,0); } // Segment visited list ubyte Automap_visited[MAX_SEGMENTS]; // Map movement defines #define PITCH_DEFAULT 9000 #define ZOOM_DEFAULT i2f(20*10) #define ZOOM_MIN_VALUE i2f(20*5) #define ZOOM_MAX_VALUE i2f(20*100) #define SLIDE_SPEED (350) #define ZOOM_SPEED_FACTOR (500) //(1500) #define ROT_SPEED_DIVISOR (115000) // Function Prototypes void adjust_segment_limit(automap *am, int SegmentLimit); void draw_all_edges(automap *am); void automap_build_edge_list(automap *am); // extern void check_and_fix_matrix(vms_matrix *m); #define MAX_DROP_MULTI 2 #define MAX_DROP_SINGLE 9 extern vms_vector Matrix_scale; //how the matrix is currently scaled # define automap_draw_line g3_draw_line void automap_clear_visited() { int i; for (i=0; ipos); g3_draw_sphere(&sphere_point,obj->size); // Draw shaft of arrow vm_vec_scale_add( &arrow_pos, &obj->pos, &obj->orient.fvec, obj->size*3 ); g3_rotate_point(&arrow_point,&arrow_pos); automap_draw_line(&sphere_point, &arrow_point); // Draw right head of arrow vm_vec_scale_add( &head_pos, &obj->pos, &obj->orient.fvec, obj->size*2 ); vm_vec_scale_add2( &head_pos, &obj->orient.rvec, obj->size*1 ); g3_rotate_point(&head_point,&head_pos); automap_draw_line(&arrow_point, &head_point); // Draw left head of arrow vm_vec_scale_add( &head_pos, &obj->pos, &obj->orient.fvec, obj->size*2 ); vm_vec_scale_add2( &head_pos, &obj->orient.rvec, obj->size*(-1) ); g3_rotate_point(&head_point,&head_pos); automap_draw_line(&arrow_point, &head_point); // Draw player's up vector vm_vec_scale_add( &arrow_pos, &obj->pos, &obj->orient.uvec, obj->size*2 ); g3_rotate_point(&arrow_point,&arrow_pos); automap_draw_line(&sphere_point, &arrow_point); } void name_frame(automap *am) { char name_level[128]; if (Current_level_num > 0) sprintf(name_level, "%s %i: ",TXT_LEVEL, Current_level_num); else name_level[0] = 0; strcat(name_level, Current_level_name); gr_set_curfont(GAME_FONT); gr_set_fontcolor(am->green_31,-1); gr_printf((SWIDTH/64),(SHEIGHT/48),"%s", name_level); } void draw_automap(automap *am) { int i; int color; object * objp; g3s_point sphere_point; if ( am->leave_mode==0 && am->controls.automap_state && (timer_query()-am->entry_time)>LEAVE_TIME) am->leave_mode = 1; gr_set_current_canvas(NULL); show_fullscr(&am->automap_background); gr_set_curfont(HUGE_FONT); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); if (!MacHog) gr_string((SWIDTH/8), (SHEIGHT/16), TXT_AUTOMAP); else gr_string(80*(SWIDTH/640.0), 36*(SHEIGHT/480.0), TXT_AUTOMAP); gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); if (!MacHog) { gr_string((SWIDTH/4.923), (SHEIGHT/1.126), TXT_TURN_SHIP); gr_string((SWIDTH/4.923), (SHEIGHT/1.083), TXT_SLIDE_UPDOWN); gr_string((SWIDTH/4.923), (SHEIGHT/1.043), "F9/F10 Changes viewing distance"); } else { // for the Mac automap they're shown up the top, hence the different layout gr_string(265*(SWIDTH/640.0), 27*(SHEIGHT/480.0), TXT_TURN_SHIP); gr_string(265*(SWIDTH/640.0), 44*(SHEIGHT/480.0), TXT_SLIDE_UPDOWN); gr_string(265*(SWIDTH/640.0), 61*(SHEIGHT/480.0), "F9/F10 Changes viewing distance"); } gr_set_current_canvas(&am->automap_view); gr_clear_canvas(BM_XRGB(0,0,0)); g3_start_frame(); render_start_frame(); if (!PlayerCfg.AutomapFreeFlight) vm_vec_scale_add(&am->view_position,&am->view_target,&am->viewMatrix.fvec,-am->viewDist); g3_set_view_matrix(&am->view_position,&am->viewMatrix,am->zoom); draw_all_edges(am); // Draw player... #ifdef NETWORK if (Game_mode & GM_TEAM) color = get_team(Player_num); else #endif color = Player_num; // Note link to above if! gr_setcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b)); draw_player(&Objects[Players[Player_num].objnum]); // Draw player(s)... #ifdef NETWORK if ( (Game_mode & (GM_TEAM | GM_MULTI_COOP)) || (Netgame.game_flags & NETGAME_FLAG_SHOW_MAP) ) { for (i=0; itype ) { case OBJ_HOSTAGE: gr_setcolor(am->hostage_color); g3_rotate_point(&sphere_point,&objp->pos); g3_draw_sphere(&sphere_point,objp->size); break; case OBJ_POWERUP: if ( Automap_visited[objp->segnum] ) { if ( (objp->id==POW_KEY_RED) || (objp->id==POW_KEY_BLUE) || (objp->id==POW_KEY_GOLD) ) { switch (objp->id) { case POW_KEY_RED: gr_setcolor(BM_XRGB(63, 5, 5)); break; case POW_KEY_BLUE: gr_setcolor(BM_XRGB(5, 5, 63)); break; case POW_KEY_GOLD: gr_setcolor(BM_XRGB(63, 63, 10)); break; default: Error("Illegal key type: %i", objp->id); } g3_rotate_point(&sphere_point,&objp->pos); g3_draw_sphere(&sphere_point,objp->size*4); } } break; } } g3_end_frame(); name_frame(am); if (PlayerCfg.MouseFlightSim && PlayerCfg.MouseFSIndicator) show_mousefs_indicator(am->controls.raw_mouse_axis[0], am->controls.raw_mouse_axis[1], am->controls.raw_mouse_axis[2], GWIDTH-(GHEIGHT/8), GHEIGHT-(GHEIGHT/8), GHEIGHT/5); am->t2 = timer_query(); while (am->t2 - am->t1 < F1_0 / (GameCfg.VSync?MAXIMUM_FPS:GameArg.SysMaxFPS)) // ogl is fast enough that the automap can read the input too fast and you start to turn really slow. So delay a bit (and free up some cpu :) { if (GameArg.SysUseNiceFPS && !GameCfg.VSync) timer_delay(f1_0 / GameArg.SysMaxFPS - (am->t2 - am->t1)); timer_update(); am->t2 = timer_query(); } if (am->pause_game) { FrameTime=am->t2-am->t1; calc_d_tick(); } am->t1 = am->t2; } extern int set_segment_depths(int start_seg, ubyte *segbuf); #define MAP_BACKGROUND_FILENAME (((SWIDTH>=640&&SHEIGHT>=480) && PHYSFSX_exists("maph.pcx",1))?"MAPH.PCX":"MAP.PCX") int automap_key_command(window *wind, d_event *event, automap *am) { int c = event_key_get(event); switch (c) { case KEY_PRINT_SCREEN: { gr_set_current_canvas(NULL); save_screen_shot(1); return 1; } case KEY_ESC: if (am->leave_mode==0) { window_close(wind); return 1; } return 1; case KEY_ALTED+KEY_F: // Alt+F shows full map, if cheats enabled if (cheats.enabled) { cheats.fullautomap = !cheats.fullautomap; automap_build_edge_list(am); } return 1; #ifndef NDEBUG case KEY_DEBUGGED+KEY_F: { int i; for (i=0; i<=Highest_segment_index; i++ ) Automap_visited[i] = 1; automap_build_edge_list(am); am->max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); am->segment_limit = am->max_segments_away; adjust_segment_limit(am, am->segment_limit); } return 1; #endif case KEY_F9: if (am->segment_limit > 1) { am->segment_limit--; adjust_segment_limit(am, am->segment_limit); } return 1; case KEY_F10: if (am->segment_limit < am->max_segments_away) { am->segment_limit++; adjust_segment_limit(am, am->segment_limit); } return 1; } return 0; } int automap_process_input(window *wind, d_event *event, automap *am) { vms_matrix tempm; Controls = am->controls; kconfig_read_controls(event, 1); am->controls = Controls; memset(&Controls, 0, sizeof(control_info)); if ( !am->controls.automap_state && (am->leave_mode==1) ) { window_close(wind); return 1; } if ( am->controls.automap_count > 0) { am->controls.automap_count = 0; if (am->leave_mode==0) { window_close(wind); return 1; } } if (PlayerCfg.AutomapFreeFlight) { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewMatrix = Objects[Players[Player_num].objnum].orient; vm_vec_scale_add(&am->view_position, &Objects[Players[Player_num].objnum].pos, &am->viewMatrix.fvec, -ZOOM_DEFAULT ); am->controls.fire_primary_count = 0; } if (am->controls.pitch_time || am->controls.heading_time || am->controls.bank_time) { vms_angvec tangles; vms_matrix new_m; tangles.p = fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h = fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b = fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); vm_angles_2_matrix(&tempm, &tangles); vm_matrix_x_matrix(&new_m,&am->viewMatrix,&tempm); am->viewMatrix = new_m; check_and_fix_matrix(&am->viewMatrix); } if ( am->controls.forward_thrust_time || am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vm_vec_scale_add2( &am->view_position, &am->viewMatrix.fvec, am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); // Crude wrapping check if (am->view_position.x > F1_0*32000) am->view_position.x = F1_0*32000; if (am->view_position.x < -F1_0*32000) am->view_position.x = -F1_0*32000; if (am->view_position.y > F1_0*32000) am->view_position.y = F1_0*32000; if (am->view_position.y < -F1_0*32000) am->view_position.y = -F1_0*32000; if (am->view_position.z > F1_0*32000) am->view_position.z = F1_0*32000; if (am->view_position.z < -F1_0*32000) am->view_position.z = -F1_0*32000; } } else { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewDist = ZOOM_DEFAULT; am->tangles.p = PITCH_DEFAULT; am->tangles.h = 0; am->tangles.b = 0; am->view_target = Objects[Players[Player_num].objnum].pos; am->controls.fire_primary_count = 0; } am->viewDist -= am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR; am->tangles.p += fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); am->tangles.h += fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); am->tangles.b += fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = am->view_target; tangles1 = am->tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &am->view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) am->view_target = old_vt; } vm_angles_2_matrix(&tempm,&am->tangles); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( am->viewDist < ZOOM_MIN_VALUE ) am->viewDist = ZOOM_MIN_VALUE; if ( am->viewDist > ZOOM_MAX_VALUE ) am->viewDist = ZOOM_MAX_VALUE; } return 0; } int automap_handler(window *wind, d_event *event, automap *am) { switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); event_toggle_focus(1); key_toggle_repeat(0); break; case EVENT_WINDOW_DEACTIVATED: event_toggle_focus(0); key_toggle_repeat(1); break; case EVENT_IDLE: case EVENT_JOYSTICK_BUTTON_UP: case EVENT_JOYSTICK_BUTTON_DOWN: case EVENT_JOYSTICK_MOVED: case EVENT_MOUSE_BUTTON_UP: case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_MOVED: automap_process_input(wind, event, am); break; case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: { int kret = automap_key_command(wind, event, am); if (!kret) automap_process_input(wind, event, am); return kret; } case EVENT_WINDOW_DRAW: draw_automap(am); break; case EVENT_WINDOW_CLOSE: if (!am->pause_game) ConsoleObject->mtype.phys_info.flags |= am->old_wiggle; // Restore wiggle event_toggle_focus(0); key_toggle_repeat(1); #ifdef OGL gr_free_bitmap_data(&am->automap_background); #endif d_free(am->edges); d_free(am->drawingListBright); d_free(am); window_set_visible(Game_wind, 1); Automap_active = 0; return 0; // continue closing break; default: return 0; break; } return 1; } void do_automap( int key_code ) { int pcx_error; ubyte pal[256*3]; window *automap_wind = NULL; automap *am; MALLOC(am, automap, 1); if (am) { memset(am, 0, sizeof(automap)); automap_wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *)) automap_handler, am); } if (automap_wind == NULL) { Warning("Out of memory"); return; } am->leave_mode = 0; am->pause_game = 1; // Set to 1 if everything is paused during automap...No pause during net. am->max_segments_away = 0; am->segment_limit = 1; am->num_edges = 0; am->highest_edge_index = -1; am->max_edges = Num_segments*12; MALLOC(am->edges, Edge_info, am->max_edges); MALLOC(am->drawingListBright, int, am->max_edges); if (!am->edges || !am->drawingListBright) { if (am->edges) d_free(am->edges); if (am->drawingListBright) d_free(am->drawingListBright); Warning("Out of memory"); return; } am->zoom = 0x9000; am->farthest_dist = (F1_0 * 20 * 50); // 50 segments away am->viewDist = 0; init_automap_colors(am); key_code = key_code; // disable warning... if ((Game_mode & GM_MULTI) && (!Endlevel_sequence)) am->pause_game = 0; if (am->pause_game) { window_set_visible(Game_wind, 0); } if (!am->pause_game) { am->old_wiggle = ConsoleObject->mtype.phys_info.flags & PF_WIGGLE; // Save old wiggle ConsoleObject->mtype.phys_info.flags &= ~PF_WIGGLE; // Turn off wiggle } //Max_edges = min(MAX_EDGES_FROM_VERTS(Num_vertices),MAX_EDGES); //make maybe smaller than max gr_set_current_canvas(NULL); automap_build_edge_list(am); if ( am->viewDist==0 ) am->viewDist = ZOOM_DEFAULT; am->viewMatrix = Objects[Players[Player_num].objnum].orient; am->tangles.p = PITCH_DEFAULT; am->tangles.h = 0; am->tangles.b = 0; am->view_target = Objects[Players[Player_num].objnum].pos; if (PlayerCfg.AutomapFreeFlight) vm_vec_scale_add(&am->view_position, &Objects[Players[Player_num].objnum].pos, &am->viewMatrix.fvec, -ZOOM_DEFAULT ); am->t1 = am->entry_time = timer_query(); am->t2 = am->t1; //Fill in Automap_visited from Objects[Players[Player_num].objnum].segnum am->max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); am->segment_limit = am->max_segments_away; adjust_segment_limit(am, am->segment_limit); // ZICO - code from above to show frame in OGL correctly. Redundant, but better readable. // KREATOR - Now applies to all platforms so double buffering is supported gr_init_bitmap_data (&am->automap_background); pcx_error = pcx_read_bitmap(MAP_BACKGROUND_FILENAME, &am->automap_background, BM_LINEAR, pal); if (pcx_error != PCX_ERROR_NONE) Error("File %s - PCX error: %s", MAP_BACKGROUND_FILENAME, pcx_errormsg(pcx_error)); gr_remap_bitmap_good(&am->automap_background, pal, -1, -1); if (!MacHog) gr_init_sub_canvas(&am->automap_view, &grd_curscreen->sc_canvas, (SWIDTH/23), (SHEIGHT/6), (SWIDTH/1.1), (SHEIGHT/1.45)); else gr_init_sub_canvas(&am->automap_view, &grd_curscreen->sc_canvas, 38*(SWIDTH/640.0), 77*(SHEIGHT/480.0), 564*(SWIDTH/640.0), 381*(SHEIGHT/480.0)); gr_palette_load( gr_palette ); Automap_active = 1; } void adjust_segment_limit(automap *am, int SegmentLimit) { int i,e1; Edge_info * e; for (i=0; i<=am->highest_edge_index; i++ ) { e = &am->edges[i]; e->flags |= EF_TOO_FAR; for (e1=0; e1num_faces; e1++ ) { if ( Automap_visited[e->segnum[e1]] <= SegmentLimit ) { e->flags &= (~EF_TOO_FAR); break; } } } } void draw_all_edges(automap *am) { g3s_codes cc; int i,j,nbright; ubyte nfacing,nnfacing; Edge_info *e; vms_vector *tv1; fix distance; fix min_distance = 0x7fffffff; g3s_point *p1, *p2; nbright=0; for (i=0; i<=am->highest_edge_index; i++ ) { //e = &am->edges[Edge_used_list[i]]; e = &am->edges[i]; if (!(e->flags & EF_USED)) continue; if ( e->flags & EF_TOO_FAR) continue; if (e->flags&EF_FRONTIER) { // A line that is between what we have seen and what we haven't if ( (!(e->flags&EF_SECRET))&&(e->color==am->wall_normal_color)) continue; // If a line isn't secret and is normal color, then don't draw it } cc=rotate_list(2,e->verts); distance = Segment_points[e->verts[1]].p3_z; if (min_distance>distance ) min_distance = distance; if (!cc.uand) { //all off screen? nfacing = nnfacing = 0; tv1 = &Vertices[e->verts[0]]; j = 0; while( jnum_faces && (nfacing==0 || nnfacing==0) ) { #ifdef COMPACT_SEGS vms_vector temp_v; get_side_normal(&Segments[e->segnum[j]], e->sides[j], 0, &temp_v ); if (!g3_check_normal_facing( tv1, &temp_v ) ) #else if (!g3_check_normal_facing( tv1, &Segments[e->segnum[j]].sides[e->sides[j]].normals[0] ) ) #endif nfacing++; else nnfacing++; j++; } if ( nfacing && nnfacing ) { // a contour line am->drawingListBright[nbright++] = e-am->edges; } else if ( e->flags&(EF_DEFINING|EF_GRATE) ) { if ( nfacing == 0 ) { if ( e->flags & EF_NO_FADE ) gr_setcolor( e->color ); else gr_setcolor( gr_fade_table[e->color+256*8] ); g3_draw_line( &Segment_points[e->verts[0]], &Segment_points[e->verts[1]] ); } else { am->drawingListBright[nbright++] = e-am->edges; } } } } if ( min_distance < 0 ) min_distance = 0; // Sort the bright ones using a shell sort { int t; int i, j, incr, v1, v2; incr = nbright / 2; while( incr > 0 ) { for (i=incr; i=0 ) { // compare element j and j+incr v1 = am->edges[am->drawingListBright[j]].verts[0]; v2 = am->edges[am->drawingListBright[j+incr]].verts[0]; if (Segment_points[v1].p3_z < Segment_points[v2].p3_z) { // If not in correct order, them swap 'em t=am->drawingListBright[j+incr]; am->drawingListBright[j+incr]=am->drawingListBright[j]; am->drawingListBright[j]=t; j -= incr; } else break; } } incr = incr / 2; } } // Draw the bright ones for (i=0; iedges[am->drawingListBright[i]]; p1 = &Segment_points[e->verts[0]]; p2 = &Segment_points[e->verts[1]]; dist = p1->p3_z - min_distance; // Make distance be 1.0 to 0.0, where 0.0 is 10 segments away; if ( dist < 0 ) dist=0; if ( dist >= am->farthest_dist ) continue; if ( e->flags & EF_NO_FADE ) { gr_setcolor( e->color ); } else { dist = F1_0 - fixdiv( dist, am->farthest_dist ); color = f2i( dist*31 ); gr_setcolor( gr_fade_table[e->color+color*256] ); } g3_draw_line( p1, p2 ); } } //================================================================== // // All routines below here are used to build the Edge list // //================================================================== //finds edge, filling in edge_ptr. if found old edge, returns index, else return -1 static int automap_find_edge(automap *am, int v0,int v1,Edge_info **edge_ptr) { long vv, evv; int hash, oldhash; int ret, ev0, ev1; vv = (v1<<16) + v0; oldhash = hash = ((v0*5+v1) % am->max_edges); ret = -1; while (ret==-1) { ev0 = am->edges[hash].verts[0]; ev1 = am->edges[hash].verts[1]; evv = (ev1<<16)+ev0; if (am->edges[hash].num_faces == 0 ) ret=0; else if (evv == vv) ret=1; else { if (++hash==am->max_edges) hash=0; if (hash==oldhash) Error("Edge list full!"); } } *edge_ptr = &am->edges[hash]; if (ret == 0) return -1; else return hash; } void add_one_edge( automap *am, int va, int vb, ubyte color, ubyte side, int segnum, int hidden, int grate, int no_fade ) { int found; Edge_info *e; int tmp; if ( am->num_edges >= am->max_edges) { // GET JOHN! (And tell him that his // MAX_EDGES_FROM_VERTS formula is hosed.) // If he's not around, save the mine, // and send him mail so he can look // at the mine later. Don't modify it. // This is important if this happens. Int3(); // LOOK ABOVE!!!!!! return; } if ( va > vb ) { tmp = va; va = vb; vb = tmp; } found = automap_find_edge(am,va,vb,&e); if (found == -1) { e->verts[0] = va; e->verts[1] = vb; e->color = color; e->num_faces = 1; e->flags = EF_USED | EF_DEFINING; // Assume a normal line e->sides[0] = side; e->segnum[0] = segnum; //Edge_used_list[am->num_edges] = e-am->edges; if ( (e-am->edges) > am->highest_edge_index ) am->highest_edge_index = e - am->edges; am->num_edges++; } else { if ( color != am->wall_normal_color ) e->color = color; if ( e->num_faces < 4 ) { e->sides[e->num_faces] = side; e->segnum[e->num_faces] = segnum; e->num_faces++; } } if ( grate ) e->flags |= EF_GRATE; if ( hidden ) e->flags|=EF_SECRET; // Mark this as a hidden edge if ( no_fade ) e->flags |= EF_NO_FADE; } void add_one_unknown_edge( automap *am, int va, int vb ) { int found; Edge_info *e; int tmp; if ( va > vb ) { tmp = va; va = vb; vb = tmp; } found = automap_find_edge(am,va,vb,&e); if (found != -1) e->flags|=EF_FRONTIER; // Mark as a border edge } #ifndef _GAMESEQ_H extern obj_position Player_init[]; #endif void add_segment_edges(automap *am, segment *seg) { int is_grate, no_fade; ubyte color; int sn; int segnum = seg-Segments; int hidden_flag; for (sn=0;snchildren[sn] == -1) { color = am->wall_normal_color; } switch( seg->special ) { case SEGMENT_IS_FUELCEN: color = BM_XRGB( 29, 27, 13 ); break; case SEGMENT_IS_CONTROLCEN: if (Control_center_present) color = BM_XRGB( 29, 0, 0 ); break; case SEGMENT_IS_ROBOTMAKER: color = BM_XRGB( 29, 0, 31 ); break; } if (seg->sides[sn].wall_num > -1) { switch( Walls[seg->sides[sn].wall_num].type ) { case WALL_DOOR: if (Walls[seg->sides[sn].wall_num].keys == KEY_BLUE) { no_fade = 1; color = am->wall_door_blue; } else if (Walls[seg->sides[sn].wall_num].keys == KEY_GOLD) { no_fade = 1; color = am->wall_door_gold; } else if (Walls[seg->sides[sn].wall_num].keys == KEY_RED) { no_fade = 1; color = am->wall_door_red; } else if (!(WallAnims[Walls[seg->sides[sn].wall_num].clip_num].flags & WCF_HIDDEN)) { int connected_seg = seg->children[sn]; if (connected_seg != -1) { int connected_side = find_connect_side(seg, &Segments[connected_seg]); int keytype = Walls[Segments[connected_seg].sides[connected_side].wall_num].keys; if ((keytype != KEY_BLUE) && (keytype != KEY_GOLD) && (keytype != KEY_RED)) color = am->wall_door_color; else { switch (Walls[Segments[connected_seg].sides[connected_side].wall_num].keys) { case KEY_BLUE: color = am->wall_door_blue; no_fade = 1; break; case KEY_GOLD: color = am->wall_door_gold; no_fade = 1; break; case KEY_RED: color = am->wall_door_red; no_fade = 1; break; default: Error("Inconsistent data. Supposed to be a colored wall, but not blue, gold or red.\n"); } } } } else { color = am->wall_normal_color; hidden_flag = 1; } break; case WALL_CLOSED: // Make grates draw properly if (WALL_IS_DOORWAY(seg,sn) & WID_RENDPAST_FLAG) is_grate = 1; else hidden_flag = 1; color = am->wall_normal_color; break; case WALL_BLASTABLE: // Hostage doors color = am->wall_door_color; break; } } if (segnum==Player_init[Player_num].segnum) color = BM_XRGB(31,0,31); if ( color != 255 ) { // If they have a map powerup, draw unvisited areas in dark blue. if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL && (!Automap_visited[segnum])) color = BM_XRGB( 0, 0, 25 ); get_side_verts(vertex_list,segnum,sn); add_one_edge( am, vertex_list[0], vertex_list[1], color, sn, segnum, hidden_flag, 0, no_fade ); add_one_edge( am, vertex_list[1], vertex_list[2], color, sn, segnum, hidden_flag, 0, no_fade ); add_one_edge( am, vertex_list[2], vertex_list[3], color, sn, segnum, hidden_flag, 0, no_fade ); add_one_edge( am, vertex_list[3], vertex_list[0], color, sn, segnum, hidden_flag, 0, no_fade ); if ( is_grate ) { add_one_edge( am, vertex_list[0], vertex_list[2], color, sn, segnum, hidden_flag, 1, no_fade ); add_one_edge( am, vertex_list[1], vertex_list[3], color, sn, segnum, hidden_flag, 1, no_fade ); } } } } // Adds all the edges from a segment we haven't visited yet. void add_unknown_segment_edges(automap *am, segment *seg) { int sn; int segnum = seg-Segments; for (sn=0;snchildren[sn] == -1) { get_side_verts(vertex_list,segnum,sn); add_one_unknown_edge( am, vertex_list[0], vertex_list[1] ); add_one_unknown_edge( am, vertex_list[1], vertex_list[2] ); add_one_unknown_edge( am, vertex_list[2], vertex_list[3] ); add_one_unknown_edge( am, vertex_list[3], vertex_list[0] ); } } } void automap_build_edge_list(automap *am) { int i,e1,e2,s; Edge_info * e; // clear edge list for (i=0; imax_edges; i++) { am->edges[i].num_faces = 0; am->edges[i].flags = 0; } am->num_edges = 0; am->highest_edge_index = -1; if (cheats.fullautomap || (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL) ) { // Cheating, add all edges as visited for (s=0; s<=Highest_segment_index; s++) #ifdef EDITOR if (Segments[s].segnum != -1) #endif { add_segment_edges(am, &Segments[s]); } } else { // Not cheating, add visited edges, and then unvisited edges for (s=0; s<=Highest_segment_index; s++) #ifdef EDITOR if (Segments[s].segnum != -1) #endif if (Automap_visited[s]) { add_segment_edges(am, &Segments[s]); } for (s=0; s<=Highest_segment_index; s++) #ifdef EDITOR if (Segments[s].segnum != -1) #endif if (!Automap_visited[s]) { add_unknown_segment_edges(am, &Segments[s]); } } // Find unnecessary lines (These are lines that don't have to be drawn because they have small curvature) for (i=0; i<=am->highest_edge_index; i++ ) { e = &am->edges[i]; if (!(e->flags&EF_USED)) continue; for (e1=0; e1num_faces; e1++ ) { for (e2=1; e2num_faces; e2++ ) { if ( (e1 != e2) && (e->segnum[e1] != e->segnum[e2]) ) { #ifdef COMPACT_SEGS vms_vector v1, v2; get_side_normal(&Segments[e->segnum[e1]], e->sides[e1], 0, &v1 ); get_side_normal(&Segments[e->segnum[e2]], e->sides[e2], 0, &v2 ); if ( vm_vec_dot(&v1,&v2) > (F1_0-(F1_0/10)) ) { #else if ( vm_vec_dot( &Segments[e->segnum[e1]].sides[e->sides[e1]].normals[0], &Segments[e->segnum[e2]].sides[e->sides[e2]].normals[0] ) > (F1_0-(F1_0/10)) ) { #endif e->flags &= (~EF_DEFINING); break; } } } if (!(e->flags & EF_DEFINING)) break; } } } dxx-rebirth-0.58.1-d1x/main/automap.h000066400000000000000000000017201217717257200173150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes for auto-map stuff. * */ #ifndef _AUTOMAP_H #define _AUTOMAP_H extern int Automap_active; extern void do_automap(int key_code); extern void automap_clear_visited(); extern ubyte Automap_visited[MAX_SEGMENTS]; #endif dxx-rebirth-0.58.1-d1x/main/bm.c000066400000000000000000000170701217717257200162450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Bitmap and palette loading functions. * */ #include #include #include #include "pstypes.h" #include "inferno.h" #include "gr.h" #include "bm.h" #include "u_mem.h" #include "dxxerror.h" #include "object.h" #include "vclip.h" #include "effects.h" #include "polyobj.h" #include "wall.h" #include "textures.h" #include "game.h" #include "multi.h" #include "iff.h" #include "hostage.h" #include "powerup.h" #include "sounds.h" #include "piggy.h" #include "aistruct.h" #include "robot.h" #include "weapon.h" #include "gauges.h" #include "player.h" #include "fuelcen.h" #include "endlevel.h" #include "cntrlcen.h" #include "rle.h" #ifdef EDITOR #include "editor/texpage.h" #endif ubyte Sounds[MAX_SOUNDS]; ubyte AltSounds[MAX_SOUNDS]; #ifdef EDITOR int Num_object_subtypes = 1; #endif int Num_total_object_types; sbyte ObjType[MAX_OBJTYPE]; sbyte ObjId[MAX_OBJTYPE]; fix ObjStrength[MAX_OBJTYPE]; //for each model, a model number for dying & dead variants, or -1 if none int Dying_modelnums[MAX_POLYGON_MODELS]; int Dead_modelnums[MAX_POLYGON_MODELS]; //right now there's only one player ship, but we can have another by //adding an array and setting the pointer to the active ship. player_ship only_player_ship,*Player_ship=&only_player_ship; //----------------- Miscellaneous bitmap pointers --------------- int Num_cockpits = 0; bitmap_index cockpit_bitmap[N_COCKPIT_BITMAPS]; //---------------- Variables for wall textures ------------------ int Num_tmaps; tmap_info TmapInfo[MAX_TEXTURES]; //---------------- Variables for object textures ---------------- int First_multi_bitmap_num=-1; bitmap_index ObjBitmaps[MAX_OBJ_BITMAPS]; ushort ObjBitmapPtrs[MAX_OBJ_BITMAPS]; // These point back into ObjBitmaps, since some are used twice. /* * reads n tmap_info structs from a PHYSFS_file */ int tmap_info_read_n(tmap_info *ti, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) { PHYSFS_read(fp, TmapInfo[i].filename, 13, 1); ti[i].flags = PHYSFSX_readByte(fp); ti[i].lighting = PHYSFSX_readFix(fp); ti[i].damage = PHYSFSX_readFix(fp); ti[i].eclip_num = PHYSFSX_readInt(fp); } return i; } void gamedata_close() { free_polygon_models(); free_endlevel_data(); rle_cache_close(); piggy_close(); } //----------------------------------------------------------------- // Initializes game properties data (including texture caching system) and sound data. int gamedata_init() { int retval; init_polygon_models(); init_endlevel();//adb: added, is also in bm_init_use_tbl (Chris: *Was* in bm_init_use_tbl) retval = properties_init(); // This calls properties_read_cmp if appropriate if (retval) gamedata_read_tbl(retval == PIGGY_PC_SHAREWARE); piggy_read_sounds(retval == PIGGY_PC_SHAREWARE); return 0; } // Read compiled properties data from descent.pig void properties_read_cmp(PHYSFS_file * fp) { int i; // bitmap_index is a short NumTextures = PHYSFSX_readInt(fp); bitmap_index_read_n(Textures, MAX_TEXTURES, fp ); tmap_info_read_n(TmapInfo, MAX_TEXTURES, fp); PHYSFS_read( fp, Sounds, sizeof(ubyte), MAX_SOUNDS ); PHYSFS_read( fp, AltSounds, sizeof(ubyte), MAX_SOUNDS ); Num_vclips = PHYSFSX_readInt(fp); vclip_read_n(Vclip, VCLIP_MAXNUM, fp); Num_effects = PHYSFSX_readInt(fp); eclip_read_n(Effects, MAX_EFFECTS, fp); Num_wall_anims = PHYSFSX_readInt(fp); wclip_read_n(WallAnims, MAX_WALL_ANIMS, fp); N_robot_types = PHYSFSX_readInt(fp); robot_info_read_n(Robot_info, MAX_ROBOT_TYPES, fp); N_robot_joints = PHYSFSX_readInt(fp); jointpos_read_n(Robot_joints, MAX_ROBOT_JOINTS, fp); N_weapon_types = PHYSFSX_readInt(fp); weapon_info_read_n(Weapon_info, MAX_WEAPON_TYPES, fp, 0); N_powerup_types = PHYSFSX_readInt(fp); powerup_type_info_read_n(Powerup_info, MAX_POWERUP_TYPES, fp); N_polygon_models = PHYSFSX_readInt(fp); polymodel_read_n(Polygon_models, N_polygon_models, fp); for (i=0; i= 0) TmapList[Num_tmaps++] = Effects[i].changing_wall_texture; #endif } void compute_average_rgb(grs_bitmap *bm, fix *rgb) { ubyte *buf; int i, x, y, color, count; fix t_rgb[3] = { 0, 0, 0 }; rgb[0] = rgb[1] = rgb[2] = 0; if (!bm->bm_data) return; MALLOC(buf, ubyte, bm->bm_w*bm->bm_h); memset(buf,0,bm->bm_w*bm->bm_h); if (bm->bm_flags & BM_FLAG_RLE){ unsigned char * dbits; unsigned char * sbits; int data_offset; data_offset = 1; if (bm->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)]; dbits = buf; for (i=0; i < bm->bm_h; i++ ) { gr_rle_decode(sbits,dbits); if ( bm->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)]))); else sbits += (int)bm->bm_data[4+i]; dbits += bm->bm_w; } } else { memcpy(buf, bm->bm_data, sizeof(unsigned char)*(bm->bm_w*bm->bm_h)); } i = 0; for (x = 0; x < bm->bm_h; x++) { for (y = 0; y < bm->bm_w; y++) { color = buf[i++]; t_rgb[0] = gr_palette[color*3]; t_rgb[1] = gr_palette[color*3+1]; t_rgb[2] = gr_palette[color*3+2]; if (!(color == TRANSPARENCY_COLOR || (t_rgb[0] == t_rgb[1] && t_rgb[0] == t_rgb[2]))) { rgb[0] += t_rgb[0]; rgb[1] += t_rgb[1]; rgb[2] += t_rgb[2]; count++; } } } d_free(buf); } dxx-rebirth-0.58.1-d1x/main/bm.h000066400000000000000000000055261217717257200162550ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Bitmap and Palette loading functions. * */ #ifndef _BM_H #define _BM_H #include "gr.h" #include "piggy.h" #define MAX_TEXTURES 800 #define BM_MAX_ARGS 10 //tmapinfo flags #define TMI_VOLATILE 1 //this material blows up when hit typedef struct { char filename[13]; ubyte flags; fix lighting; // 0 to 1 fix damage; //how much damage being against this does int eclip_num; //if not -1, the eclip that changes this } __pack__ tmap_info; extern int Num_object_types; #define N_COCKPIT_BITMAPS 4 extern int Num_cockpits; extern bitmap_index cockpit_bitmap[N_COCKPIT_BITMAPS]; extern int Num_tmaps; #ifdef EDITOR extern int TmapList[MAX_TEXTURES]; #endif extern tmap_info TmapInfo[MAX_TEXTURES]; //for each model, a model number for dying & dead variants, or -1 if none extern int Dying_modelnums[]; extern int Dead_modelnums[]; // Initializes properties, bitmap system, sounds... int gamedata_read_tbl(int pc_shareware); void gamedata_close(); int gamedata_init(); void bm_close(); // Initializes the Texture[] array of bmd_bitmap structures. void init_textures(); #define OL_ROBOT 1 #define OL_HOSTAGE 2 #define OL_POWERUP 3 #define OL_CONTROL_CENTER 4 #define OL_PLAYER 5 #define OL_CLUTTER 6 //some sort of misc object #define OL_EXIT 7 //the exit model for external scenes #define MAX_OBJTYPE 100 extern int Num_total_object_types; // Total number of object types, including robots, hostages, powerups, control centers, faces extern sbyte ObjType[MAX_OBJTYPE]; // Type of an object, such as Robot, eg if ObjType[11] == OL_ROBOT, then object #11 is a robot extern sbyte ObjId[MAX_OBJTYPE]; // ID of a robot, within its class, eg if ObjType[11] == 3, then object #11 is the third robot extern fix ObjStrength[MAX_OBJTYPE]; // initial strength of each object #define MAX_OBJ_BITMAPS 210 extern int Num_object_subtypes; // Number of possible IDs for the current type of object to be placed extern bitmap_index ObjBitmaps[MAX_OBJ_BITMAPS]; extern ushort ObjBitmapPtrs[MAX_OBJ_BITMAPS]; extern int First_multi_bitmap_num; void compute_average_rgb(grs_bitmap *bm, fix *rgb); #endif dxx-rebirth-0.58.1-d1x/main/bmread.c000066400000000000000000001514121217717257200171000ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to parse bitmaps.tbl * */ #include #include #include #include #include #include "pstypes.h" #include "inferno.h" #include "gr.h" #include "bm.h" #include "u_mem.h" #include "dxxerror.h" #include "object.h" #include "vclip.h" #include "effects.h" #include "polyobj.h" #include "wall.h" #include "textures.h" #include "game.h" #include "multi.h" #include "iff.h" #include "hostage.h" #include "powerup.h" #include "laser.h" #include "sounds.h" #include "piggy.h" #include "aistruct.h" #include "robot.h" #include "weapon.h" #include "gauges.h" #include "player.h" #include "fuelcen.h" #include "endlevel.h" #include "cntrlcen.h" #include "args.h" #include "text.h" #include "strutil.h" #ifdef EDITOR #include "editor/texpage.h" #endif void bm_read_eclip(int skip); void bm_read_gauges(int skip); void bm_read_wclip(int skip); void bm_read_vclip(int skip); void bm_read_sound(int skip, int pc_shareware); void bm_read_robot_ai(int skip); void bm_read_robot(int skip); void bm_read_object(int skip); void bm_read_player_ship(int skip); void bm_read_some_file(int skip); void bm_read_weapon(int skip, int unused_flag); void bm_read_powerup(int unused_flag); void bm_read_hostage(); void bm_read_hostage_face(int skip, int pc_shareware); void verify_textures(); #define BM_NONE -1 #define BM_COCKPIT 0 #define BM_TEXTURES 2 #define BM_UNUSED 3 #define BM_VCLIP 4 #define BM_EFFECTS 5 #define BM_ECLIP 6 #define BM_WEAPON 7 #define BM_DEMO 8 #define BM_ROBOTEX 9 #define BM_WALL_ANIMS 12 #define BM_WCLIP 13 #define BM_ROBOT 14 #define BM_GAUGES 20 #define MAX_BITMAPS_PER_BRUSH 30 extern player_ship only_player_ship; // In bm.c static short N_ObjBitmaps=0; static short N_ObjBitmapPtrs=0; static int Num_robot_ais = 0; int TmapList[MAX_TEXTURES]; char Powerup_names[MAX_POWERUP_TYPES][POWERUP_NAME_LENGTH]; char Robot_names[MAX_ROBOT_TYPES][ROBOT_NAME_LENGTH]; //---------------- Internal variables --------------------------- static int SuperX = -1; static int Installed=0; static char *arg; static short tmap_count = 0; static short texture_count = 0; static short clip_count = 0; static short clip_num; static short sound_num; static short frames; static float play_time; static int hit_sound = -1; static sbyte bm_flag = BM_NONE; static int abm_flag = 0; static int rod_flag = 0; static short wall_open_sound, wall_close_sound,wall_explodes,wall_blastable, wall_hidden; float vlighting=0; static int obj_eclip; static char *dest_bm; //clip number to play when destroyed static int dest_vclip; //what vclip to play when exploding static int dest_eclip; //what eclip to play when exploding static fix dest_size; //3d size of explosion static int crit_clip; //clip number to play when destroyed static int crit_flag; //flag if this is a destroyed eclip static int tmap1_flag; //flag if this is used as tmap_num (not tmap_num2) static int num_sounds=0; //------------------- Useful macros and variables --------------- #define IFTOK(str) if (!strcmp(arg, str)) char *space = { " \t" }; //--unused-- char *equal = { "=" }; char *equal_space = { " \t=" }; void remove_char( char * s, char c ) { char *p; p = strchr(s,c); if (p) *p = '\0'; } //--------------------------------------------------------------- int compute_average_pixel(grs_bitmap *new) { int row, column, color; // char *pptr; int total_red, total_green, total_blue; total_red = 0; total_green = 0; total_blue = 0; for (row=0; rowbm_h; row++) for (column=0; columnbm_w; column++) { color = gr_gpixel (new, column, row); total_red += gr_palette[color*3]; total_green += gr_palette[color*3+1]; total_blue += gr_palette[color*3+2]; } total_red /= (new->bm_h * new->bm_w); total_green /= (new->bm_h * new->bm_w); total_blue /= (new->bm_h * new->bm_w); return BM_XRGB(total_red/2, total_green/2, total_blue/2); } //--------------------------------------------------------------- // Loads a bitmap from either the piggy file, a r64 file, or a // whatever extension is passed. bitmap_index bm_load_sub(int skip, char * filename ) { bitmap_index bitmap_num; grs_bitmap * new; ubyte newpal[256*3]; int iff_error; //reference parm to avoid warning message char fname[20]; bitmap_num.index = 0; if (skip) { return bitmap_num; } removeext( filename, fname ); bitmap_num=piggy_find_bitmap( fname ); if (bitmap_num.index) { return bitmap_num; } MALLOC( new, grs_bitmap, 1 ); iff_error = iff_read_bitmap(filename,new,BM_LINEAR,newpal); if (iff_error != IFF_NO_ERROR) { Error("File %s - IFF error: %s",filename,iff_errormsg(iff_error)); } if ( iff_has_transparency ) gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX ); else gr_remap_bitmap_good( new, newpal, -1, SuperX ); new->avg_color = compute_average_pixel(new); bitmap_num = piggy_register_bitmap( new, fname, 0 ); d_free( new ); return bitmap_num; } void ab_load(int skip, char * filename, bitmap_index bmp[], int *nframes ) { grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH]; bitmap_index bi; int i; int iff_error; //reference parm to avoid warning message ubyte newpal[768]; char fname[20]; char tempname[20]; if (skip) { Assert( bogus_bitmap_initialized != 0 ); bmp[0] = piggy_register_bitmap(&bogus_bitmap, "bogus", 0); *nframes = 1; return; } removeext( filename, fname ); for (i=0; iavg_color = compute_average_pixel(bm[i]); new_bmp = piggy_register_bitmap( bm[i], tempname, 0 ); d_free( bm[i] ); bmp[i] = new_bmp; } } int ds_load(int skip, char * filename ) { int i; PHYSFS_file * cfp; digi_sound new; char fname[20]; char rawname[100]; if (skip) { // We tell piggy_register_sound it's in the pig file, when in actual fact it's in no file // This just tells piggy_close not to attempt to free it return piggy_register_sound( &bogus_sound, "bogus", 1 ); } removeext(filename, fname); sprintf( rawname, "Sounds/%s.raw", fname ); i=piggy_find_sound( fname ); if (i!=255) { return i; } cfp = PHYSFSX_openReadBuffered(rawname); if (cfp!=NULL) { #ifdef ALLEGRO new.len = PHYSFS_fileLength( cfp ); MALLOC( new.data, ubyte, new.len ); PHYSFS_read( cfp, new.data, 1, new.len ); #else new.length = PHYSFS_fileLength( cfp ); MALLOC( new.data, ubyte, new.length ); PHYSFS_read( cfp, new.data, 1, new.length ); #endif PHYSFS_close(cfp); new.bits = 8; new.freq = 11025; } else { return 255; } i = piggy_register_sound( &new, fname, 0 ); return i; } //parse a float float get_float() { char *xarg; xarg = strtok( NULL, space ); return atof( xarg ); } //parse an int int get_int() { char *xarg; xarg = strtok( NULL, space ); return atoi( xarg ); } // rotates a byte left one bit, preserving the bit falling off the right //void //rotate_left(char *c) //{ // int found; // // found = 0; // if (*c & 0x80) // found = 1; // *c = *c << 1; // if (found) // *c |= 0x01; //} #define LINEBUF_SIZE 600 int linenum; //----------------------------------------------------------------- // Initializes all properties and bitmaps from BITMAPS.TBL file. int gamedata_read_tbl(int pc_shareware) { PHYSFS_file * InfoFile; char inputline[LINEBUF_SIZE]; int i, have_bin_tbl; ObjType[0] = OL_PLAYER; ObjId[0] = 0; Num_total_object_types = 1; for (i=0; ibm_w!=64)||(bmp->bm_h!=64)||(bmp->bm_rowsize!=64) ) { j++; } } if (j) Error("There are game textures that are not 64x64"); } void set_lighting_flag(sbyte *bp) { if (vlighting < 0) *bp |= BM_FLAG_NO_LIGHTING; else *bp &= (0xff ^ BM_FLAG_NO_LIGHTING); } void set_texture_name(char *name) { strcpy ( TmapInfo[texture_count].filename, name ); REMOVE_DOTS(TmapInfo[texture_count].filename); } void bm_read_eclip(int skip) { bitmap_index bitmap; Assert(clip_num < MAX_EFFECTS); if (clip_num+1 > Num_effects) Num_effects = clip_num+1; Effects[clip_num].flags = 0; if (!abm_flag) { bitmap = bm_load_sub(skip, arg); Effects[clip_num].vc.play_time = fl2f(play_time); Effects[clip_num].vc.num_frames = frames; Effects[clip_num].vc.frame_time = fl2f(play_time)/frames; Assert(clip_count < frames); Effects[clip_num].vc.frames[clip_count] = bitmap; set_lighting_flag(&GameBitmaps[bitmap.index].bm_flags); Assert(!obj_eclip); //obj eclips for non-abm files not supported! Assert(crit_flag==0); if (clip_count == 0) { Effects[clip_num].changing_wall_texture = texture_count; Assert(tmap_count < MAX_TEXTURES); TmapList[tmap_count++] = texture_count; Textures[texture_count] = bitmap; set_texture_name(arg); Assert(texture_count < MAX_TEXTURES); texture_count++; TmapInfo[texture_count].eclip_num = clip_num; NumTextures = texture_count; } clip_count++; } else { bitmap_index bm[MAX_BITMAPS_PER_BRUSH]; abm_flag = 0; ab_load(skip, arg, bm, &Effects[clip_num].vc.num_frames ); Effects[clip_num].vc.play_time = fl2f(play_time); Effects[clip_num].vc.frame_time = Effects[clip_num].vc.play_time/Effects[clip_num].vc.num_frames; clip_count = 0; set_lighting_flag( &GameBitmaps[bm[clip_count].index].bm_flags); Effects[clip_num].vc.frames[clip_count] = bm[clip_count]; if (!obj_eclip && !crit_flag) { Effects[clip_num].changing_wall_texture = texture_count; Assert(tmap_count < MAX_TEXTURES); TmapList[tmap_count++] = texture_count; Textures[texture_count] = bm[clip_count]; set_texture_name( arg ); Assert(texture_count < MAX_TEXTURES); TmapInfo[texture_count].eclip_num = clip_num; texture_count++; NumTextures = texture_count; } if (obj_eclip) { if (Effects[clip_num].changing_object_texture == -1) { //first time referenced Effects[clip_num].changing_object_texture = N_ObjBitmaps; // XChange ObjectBitmaps N_ObjBitmaps++; } ObjBitmaps[Effects[clip_num].changing_object_texture] = Effects[clip_num].vc.frames[0]; } //if for an object, Effects_bm_ptrs set in object load for(clip_count=1;clip_count < Effects[clip_num].vc.num_frames; clip_count++) { set_lighting_flag( &GameBitmaps[bm[clip_count].index].bm_flags); Effects[clip_num].vc.frames[clip_count] = bm[clip_count]; } } Effects[clip_num].crit_clip = crit_clip; Effects[clip_num].sound_num = sound_num; if (dest_bm) { //deal with bitmap for blown up clip char short_name[13]; int i; strcpy(short_name,dest_bm); REMOVE_DOTS(short_name); for (i=0;i-1) && (clip_count==0) ) Error( "Wall Clip %d is already used!", clip_num ); WallAnims[clip_num].play_time = fl2f(play_time); WallAnims[clip_num].num_frames = frames; //WallAnims[clip_num].frame_time = fl2f(play_time)/frames; Assert(clip_count < frames); WallAnims[clip_num].frames[clip_count++] = texture_count; WallAnims[clip_num].open_sound = wall_open_sound; WallAnims[clip_num].close_sound = wall_close_sound; Textures[texture_count] = bitmap; set_lighting_flag(&GameBitmaps[bitmap.index].bm_flags); set_texture_name( arg ); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; } else { bitmap_index bm[MAX_BITMAPS_PER_BRUSH]; int nframes; if ( (WallAnims[clip_num].num_frames>-1) ) Error( "AB_Wall clip %d is already used!", clip_num ); abm_flag = 0; ab_load(skip, arg, bm, &nframes ); WallAnims[clip_num].num_frames = nframes; WallAnims[clip_num].play_time = fl2f(play_time); //WallAnims[clip_num].frame_time = fl2f(play_time)/nframes; WallAnims[clip_num].open_sound = wall_open_sound; WallAnims[clip_num].close_sound = wall_close_sound; WallAnims[clip_num].close_sound = wall_close_sound; strcpy(WallAnims[clip_num].filename, arg); REMOVE_DOTS(WallAnims[clip_num].filename); if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); for (clip_count=0;clip_count < WallAnims[clip_num].num_frames; clip_count++) { Textures[texture_count] = bm[clip_count]; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); WallAnims[clip_num].frames[clip_count] = texture_count; REMOVE_DOTS(arg); sprintf( TmapInfo[texture_count].filename, "%s#%d", arg, clip_count); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; } } } void bm_read_vclip(int skip) { bitmap_index bi; Assert(clip_num < VCLIP_MAXNUM); if (!abm_flag) { if ( (Vclip[clip_num].num_frames>-1) && (clip_count==0) ) Error( "Vclip %d is already used!", clip_num ); bi = bm_load_sub(skip, arg); Vclip[clip_num].play_time = fl2f(play_time); Vclip[clip_num].num_frames = frames; Vclip[clip_num].frame_time = fl2f(play_time)/frames; Vclip[clip_num].light_value = fl2f(vlighting); Vclip[clip_num].sound_num = sound_num; set_lighting_flag(&GameBitmaps[bi.index].bm_flags); Assert(clip_count < frames); Vclip[clip_num].frames[clip_count++] = bi; if (rod_flag) { rod_flag=0; Vclip[clip_num].flags |= VF_ROD; } } else { bitmap_index bm[MAX_BITMAPS_PER_BRUSH]; abm_flag = 0; if ( (Vclip[clip_num].num_frames>-1) ) Error( "AB_Vclip %d is already used!", clip_num ); ab_load(skip, arg, bm, &Vclip[clip_num].num_frames ); if (rod_flag) { //int i; rod_flag=0; Vclip[clip_num].flags |= VF_ROD; } Vclip[clip_num].play_time = fl2f(play_time); Vclip[clip_num].frame_time = fl2f(play_time)/Vclip[clip_num].num_frames; Vclip[clip_num].light_value = fl2f(vlighting); Vclip[clip_num].sound_num = sound_num; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); for (clip_count=0;clip_count < Vclip[clip_num].num_frames; clip_count++) { set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); Vclip[clip_num].frames[clip_count] = bm[clip_count]; } } } // ------------------------------------------------------------------------------ void get4fix(fix *fixp) { char *curtext; int i; for (i=0; i 179) { ff = 179; } ff = ff/360; tt = fl2f(ff); fix_sincos(tt, &temp, &fovp[i]); } } void clear_to_end_of_line(void) { arg = strtok( NULL, space ); while (arg != NULL) arg = strtok( NULL, space ); } void bm_read_sound(int skip, int pc_shareware) { int sound_num; int alt_sound_num; sound_num = get_int(); alt_sound_num = pc_shareware ? sound_num : get_int(); if ( sound_num>=MAX_SOUNDS ) Error( "Too many sound files.\n" ); if (sound_num >= num_sounds) num_sounds = sound_num+1; arg = strtok(NULL, space); Sounds[sound_num] = ds_load(skip, arg); if ( alt_sound_num == 0 ) AltSounds[sound_num] = sound_num; else if (alt_sound_num < 0 ) AltSounds[sound_num] = 255; else AltSounds[sound_num] = alt_sound_num; if (Sounds[sound_num] == 255) Error("Can't load soundfile <%s>",arg); } // ------------------------------------------------------------------------------ void bm_read_robot_ai(int skip) { char *robotnum_text; int robotnum; robot_info *robptr; robotnum_text = strtok(NULL, space); robotnum = atoi(robotnum_text); Assert(robotnum < MAX_ROBOT_TYPES); robptr = &Robot_info[robotnum]; Assert(robotnum == Num_robot_ais); //make sure valid number if (skip) { Num_robot_ais++; clear_to_end_of_line(); return; } Num_robot_ais++; get4fix(robptr->field_of_view); get4fix(robptr->firing_wait); get4byte(robptr->rapidfire_count); get4fix(robptr->turn_time); fix fire_power[NDL]; // damage done by a hit from this robot fix shield[NDL]; // shield strength of this robot get4fix(fire_power); get4fix(shield); get4fix(robptr->max_speed); get4fix(robptr->circle_distance); get4byte(robptr->evade_speed); robptr->always_0xabcd = 0xabcd; adjust_field_of_view(robptr->field_of_view); } // ---------------------------------------------------------------------------------------------- //this will load a bitmap for a polygon models. it puts the bitmap into //the array ObjBitmaps[], and also deals with animating bitmaps //returns a pointer to the bitmap grs_bitmap *load_polymodel_bitmap(int skip, char *name) { Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS); // Assert( N_ObjBitmaps == N_ObjBitmapPtrs ); if (name[0] == '%') { //an animating bitmap! int eclip_num; eclip_num = atoi(name+1); if (Effects[eclip_num].changing_object_texture == -1) { //first time referenced Effects[eclip_num].changing_object_texture = N_ObjBitmaps; ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; N_ObjBitmaps++; } else { ObjBitmapPtrs[N_ObjBitmapPtrs++] = Effects[eclip_num].changing_object_texture; } return NULL; } else { ObjBitmaps[N_ObjBitmaps] = bm_load_sub(skip, name); ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; N_ObjBitmaps++; return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index]; } } #define MAX_MODEL_VARIANTS 4 // ------------------------------------------------------------------------------ void bm_read_robot(int skip) { char *model_name[MAX_MODEL_VARIANTS]; int n_models,i; int first_bitmap_num[MAX_MODEL_VARIANTS]; char *equal_ptr; int exp1_vclip_num=-1; int exp1_sound_num=-1; int exp2_vclip_num=-1; int exp2_sound_num=-1; fix lighting = F1_0/2; // Default fix strength = F1_0*10; // Default strength fix mass = f1_0*4; fix drag = f1_0/2; short weapon_type = 0; int g,s; char name[ROBOT_NAME_LENGTH]; int contains_count=0, contains_id=0, contains_prob=0, contains_type=0; int score_value=1000; int cloak_type=0; // Default = this robot does not cloak int attack_type=0; // Default = this robot attacks by firing (1=lunge) int boss_flag=0; // Default = robot is not a boss. int see_sound = ROBOT_SEE_SOUND_DEFAULT; int attack_sound = ROBOT_ATTACK_SOUND_DEFAULT; int claw_sound = ROBOT_CLAW_SOUND_DEFAULT; Assert(N_robot_types < MAX_ROBOT_TYPES); if (skip) { Robot_info[N_robot_types].model_num = -1; N_robot_types++; Num_total_object_types++; clear_to_end_of_line(); return; } model_name[0] = strtok( NULL, space ); first_bitmap_num[0] = N_ObjBitmapPtrs; n_models = 1; // Process bitmaps bm_flag=BM_ROBOT; arg = strtok( NULL, space ); while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' if (!d_stricmp( arg, "exp1_vclip" )) { exp1_vclip_num = atoi(equal_ptr); } else if (!d_stricmp( arg, "exp2_vclip" )) { exp2_vclip_num = atoi(equal_ptr); } else if (!d_stricmp( arg, "exp1_sound" )) { exp1_sound_num = atoi(equal_ptr); } else if (!d_stricmp( arg, "exp2_sound" )) { exp2_sound_num = atoi(equal_ptr); } else if (!d_stricmp( arg, "lighting" )) { lighting = fl2f(atof(equal_ptr)); if ( (lighting < 0) || (lighting > F1_0 )) { Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); } } else if (!d_stricmp( arg, "weapon_type" )) { weapon_type = atoi(equal_ptr); } else if (!d_stricmp( arg, "strength" )) { strength = i2f(atoi(equal_ptr)); } else if (!d_stricmp( arg, "mass" )) { mass = fl2f(atof(equal_ptr)); } else if (!d_stricmp( arg, "drag" )) { drag = fl2f(atof(equal_ptr)); } else if (!d_stricmp( arg, "contains_id" )) { contains_id = atoi(equal_ptr); } else if (!d_stricmp( arg, "contains_type" )) { contains_type = atoi(equal_ptr); } else if (!d_stricmp( arg, "contains_count" )) { contains_count = atoi(equal_ptr); } else if (!d_stricmp( arg, "contains_prob" )) { contains_prob = atoi(equal_ptr); } else if (!d_stricmp( arg, "cloak_type" )) { cloak_type = atoi(equal_ptr); } else if (!d_stricmp( arg, "attack_type" )) { attack_type = atoi(equal_ptr); } else if (!d_stricmp( arg, "boss" )) { boss_flag = atoi(equal_ptr); } else if (!d_stricmp( arg, "score_value" )) { score_value = atoi(equal_ptr); } else if (!d_stricmp( arg, "see_sound" )) { see_sound = atoi(equal_ptr); } else if (!d_stricmp( arg, "attack_sound" )) { attack_sound = atoi(equal_ptr); } else if (!d_stricmp( arg, "claw_sound" )) { claw_sound = atoi(equal_ptr); } else if (!d_stricmp( arg, "name" )) { Assert(strlen(equal_ptr) < ROBOT_NAME_LENGTH); // Oops, name too long. strcpy(name, &equal_ptr[1]); name[strlen(name)-1] = 0; } else if (!d_stricmp( arg, "simple_model" )) { model_name[n_models] = equal_ptr; first_bitmap_num[n_models] = N_ObjBitmapPtrs; n_models++; } } else { // Must be a texture specification... load_polymodel_bitmap(skip, arg); } arg = strtok( NULL, space ); } //clear out anim info for (g=0;g F1_0 )) { Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); } } else if (!d_stricmp( arg, "strength" )) { strength = fl2f(atof(equal_ptr)); } } else { // Must be a texture specification... load_polymodel_bitmap(skip, arg); } arg = strtok( NULL, space ); } if ( model_name_dead ) n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num; else n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); if (type == OL_CONTROL_CENTER) Reactors[0].n_guns = read_model_guns(model_name,Reactors[0].gun_points,Reactors[0].gun_dirs,NULL); if ( model_name_dead ) Dead_modelnums[model_num] = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL); else Dead_modelnums[model_num] = -1; if (type == -1) Error("No object type specfied for object in BITMAPS.TBL on line %d\n",linenum); ObjType[Num_total_object_types] = type; ObjId[Num_total_object_types] = model_num; ObjStrength[Num_total_object_types] = strength; Num_total_object_types++; if (type == OL_EXIT) { exit_modelnum = model_num; destroyed_exit_modelnum = Dead_modelnums[model_num]; } } void bm_read_player_ship(int skip) { char *model_name_dying=NULL; char *model_name[MAX_MODEL_VARIANTS]; int n_models=0,i; int first_bitmap_num[MAX_MODEL_VARIANTS]; char *equal_ptr; robot_info ri; int last_multi_bitmap_num=-1; // Process bitmaps bm_flag = BM_NONE; arg = strtok( NULL, space ); Player_ship->mass = Player_ship->drag = 0; //stupid defaults Player_ship->expl_vclip_num = -1; while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' if (!d_stricmp( arg, "model" )) { Assert(n_models==0); model_name[0] = equal_ptr; first_bitmap_num[0] = N_ObjBitmapPtrs; n_models = 1; } else if (!d_stricmp( arg, "simple_model" )) { model_name[n_models] = equal_ptr; first_bitmap_num[n_models] = N_ObjBitmapPtrs; n_models++; if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) last_multi_bitmap_num=N_ObjBitmapPtrs; } else if (!d_stricmp( arg, "mass" )) Player_ship->mass = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "drag" )) Player_ship->drag = fl2f(atof(equal_ptr)); // else if (!d_stricmp( arg, "low_thrust" )) // Player_ship->low_thrust = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "max_thrust" )) Player_ship->max_thrust = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "reverse_thrust" )) Player_ship->reverse_thrust = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "brakes" )) Player_ship->brakes = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "wiggle" )) Player_ship->wiggle = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "max_rotthrust" )) Player_ship->max_rotthrust = fl2f(atof(equal_ptr)); else if (!d_stricmp( arg, "dying_pof" )) model_name_dying = equal_ptr; else if (!d_stricmp( arg, "expl_vclip_num" )) Player_ship->expl_vclip_num=atoi(equal_ptr); } else if (!d_stricmp( arg, "multi_textures" )) { First_multi_bitmap_num = N_ObjBitmapPtrs; first_bitmap_num[n_models] = N_ObjBitmapPtrs; } else // Must be a texture specification... load_polymodel_bitmap(skip, arg); arg = strtok( NULL, space ); } Assert(model_name != NULL); if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) last_multi_bitmap_num=N_ObjBitmapPtrs; if (First_multi_bitmap_num==-1) first_bitmap_num[n_models] = N_ObjBitmapPtrs; #ifdef NETWORK Assert(last_multi_bitmap_num-First_multi_bitmap_num == (MAX_PLAYERS-1)*2); #endif for (i=0;imodel_num = model_num; else Polygon_models[last_model_num].simpler_model = model_num+1; last_model_num = model_num; } if ( model_name_dying ) { Assert(n_models); Dying_modelnums[Player_ship->model_num] = load_polygon_model(model_name_dying,first_bitmap_num[1]-first_bitmap_num[0],first_bitmap_num[0],NULL); } Assert(ri.n_guns == N_PLAYER_GUNS); //calc player gun positions { polymodel *pm; robot_info *r; vms_vector pnt; int mn; //submodel number int gun_num; r = &ri; pm = &Polygon_models[Player_ship->model_num]; for (gun_num=0;gun_numn_guns;gun_num++) { pnt = r->gun_points[gun_num]; mn = r->gun_submodels[gun_num]; //instance up the tree for this gun while (mn != 0) { vm_vec_add2(&pnt,&pm->submodel_offsets[mn]); mn = pm->submodel_parents[mn]; } Player_ship->gun_points[gun_num] = pnt; } } } void bm_read_some_file(int skip) { switch (bm_flag) { case BM_COCKPIT: { bitmap_index bitmap; bitmap = bm_load_sub(skip, arg); Assert( Num_cockpits < N_COCKPIT_BITMAPS ); cockpit_bitmap[Num_cockpits++] = bitmap; //bm_flag = BM_NONE; } break; case BM_GAUGES: bm_read_gauges(skip); break; case BM_WEAPON: bm_read_weapon(skip, 0); break; case BM_VCLIP: bm_read_vclip(skip); break; case BM_ECLIP: bm_read_eclip(skip); break; case BM_TEXTURES: { bitmap_index bitmap; bitmap = bm_load_sub(skip, arg); Assert(tmap_count < MAX_TEXTURES); TmapList[tmap_count++] = texture_count; Textures[texture_count] = bitmap; set_texture_name( arg ); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; } break; case BM_WCLIP: bm_read_wclip(skip); break; default: break; } } // ------------------------------------------------------------------------------ // If unused_flag is set, then this is just a placeholder. Don't actually reference vclips or load bbms. void bm_read_weapon(int skip, int unused_flag) { int i,n; int n_models=0; char *equal_ptr; char *pof_file_inner=NULL; char *model_name[MAX_MODEL_VARIANTS]; int first_bitmap_num[MAX_MODEL_VARIANTS]; int lighted; //flag for whether is a texture is lighted Assert(N_weapon_types < MAX_WEAPON_TYPES); n = N_weapon_types; N_weapon_types++; if (unused_flag) { clear_to_end_of_line(); return; } if (skip) { clear_to_end_of_line(); return; } // Initialize weapon array Weapon_info[n].render_type = WEAPON_RENDER_NONE; // 0=laser, 1=blob, 2=object Weapon_info[n].bitmap.index = 0; Weapon_info[n].model_num = -1; Weapon_info[n].model_num_inner = -1; Weapon_info[n].blob_size = 0x1000; // size of blob Weapon_info[n].flash_vclip = -1; Weapon_info[n].flash_sound = SOUND_LASER_FIRED; Weapon_info[n].flash_size = 0; Weapon_info[n].robot_hit_vclip = -1; Weapon_info[n].robot_hit_sound = -1; Weapon_info[n].wall_hit_vclip = -1; Weapon_info[n].wall_hit_sound = -1; Weapon_info[n].impact_size = 0; for (i=0; ibm_flags |= BM_FLAG_NO_LIGHTING; lighted = 1; //default for next bitmap is lighted } arg = strtok( NULL, space ); } first_bitmap_num[n_models] = N_ObjBitmapPtrs; for (i=0;i=0 && clip_num #include "dxxerror.h" #include "inferno.h" #include "cntrlcen.h" #include "game.h" #include "laser.h" #include "gameseq.h" #include "ai.h" #include "multi.h" #include "fuelcen.h" #include "wall.h" #include "object.h" #include "robot.h" #include "endlevel.h" #include "byteswap.h" reactor Reactors[MAX_REACTORS]; control_center_triggers ControlCenterTriggers; int Control_center_been_hit; int Control_center_player_been_seen; int Control_center_next_fire_time; int Control_center_present; void do_countdown_frame(); // ----------------------------------------------------------------------------- //return the position & orientation of a gun on the control center object void calc_controlcen_gun_point(reactor *reactor, object *obj,int gun_num) { vms_matrix m; vms_vector *gun_point = &obj->ctype.reactor_info.gun_pos[gun_num]; vms_vector *gun_dir = &obj->ctype.reactor_info.gun_dir[gun_num]; Assert(obj->type == OBJ_CNTRLCEN); Assert(obj->render_type==RT_POLYOBJ); Assert(gun_num < reactor->n_guns); //instance gun position & orientation vm_copy_transpose_matrix(&m,&obj->orient); vm_vec_rotate(gun_point,&reactor->gun_points[gun_num],&m); vm_vec_add2(gun_point,&obj->pos); vm_vec_rotate(gun_dir,&reactor->gun_dirs[gun_num],&m); } // ----------------------------------------------------------------------------- // Look at control center guns, find best one to fire at *objp. // Return best gun number (one whose direction dotted with vector to player is largest). // If best gun has negative dot, return -1, meaning no gun is good. int calc_best_gun(int num_guns, const object *objreactor, const vms_vector *objpos) { int i; fix best_dot; int best_gun; const vms_vector (*const gun_pos)[MAX_CONTROLCEN_GUNS] = &objreactor->ctype.reactor_info.gun_pos; const vms_vector (*const gun_dir)[MAX_CONTROLCEN_GUNS] = &objreactor->ctype.reactor_info.gun_dir; best_dot = -F1_0*2; best_gun = -1; for (i=0; i best_dot) { best_dot = dot; best_gun = i; } } Assert(best_gun != -1); // Contact Mike. This is impossible. Or maybe you're getting an unnormalized vector somewhere. if (best_dot < 0) return -1; else return best_gun; } int Dead_controlcen_object_num=-1; int Control_center_destroyed = 0; fix Countdown_timer=0; int Countdown_seconds_left=0, Total_countdown_time=0; //in whole seconds static const int Alan_pavlish_reactor_times[NDL] = {50, 45, 40, 35, 30}; // ----------------------------------------------------------------------------- // Called every frame. If control center been destroyed, then actually do something. void do_controlcen_dead_frame(void) { if ((Game_mode & GM_MULTI) && (Players[Player_num].connected != CONNECT_PLAYING)) // if out of level already there's no need for this return; if ((Dead_controlcen_object_num != -1) && (Countdown_seconds_left > 0)) if (d_rand() < FrameTime*4) create_small_fireball_on_object(&Objects[Dead_controlcen_object_num], F1_0*3, 1); if (Control_center_destroyed && !Endlevel_sequence) do_countdown_frame(); } #define COUNTDOWN_VOICE_TIME fl2f(12.75) void do_countdown_frame() { fix old_time; int fc, div_scale; if (!Control_center_destroyed) return; // Control center destroyed, rock the player's ship. fc = Countdown_seconds_left; if (fc > 16) fc = 16; // At Trainee, decrease rocking of ship by 4x. div_scale = 1; if (Difficulty_level == 0) div_scale = 4; if (d_tick_step) { ConsoleObject->mtype.phys_info.rotvel.x += (fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32))/div_scale; ConsoleObject->mtype.phys_info.rotvel.z += (fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32))/div_scale; } // Hook in the rumble sound effect here. old_time = Countdown_timer; Countdown_timer -= FrameTime; Countdown_seconds_left = f2i(Countdown_timer + F1_0*7/8); if ( (old_time > COUNTDOWN_VOICE_TIME ) && (Countdown_timer <= COUNTDOWN_VOICE_TIME) ) { digi_play_sample( SOUND_COUNTDOWN_13_SECS, F3_0 ); } if ( f2i(old_time + F1_0*7/8) != Countdown_seconds_left ) { if ( (Countdown_seconds_left>=0) && (Countdown_seconds_left<10) ) digi_play_sample( SOUND_COUNTDOWN_0_SECS+Countdown_seconds_left, F3_0 ); if ( Countdown_seconds_left==Total_countdown_time-1) digi_play_sample( SOUND_COUNTDOWN_29_SECS, F3_0 ); } if (Countdown_timer > 0) { fix size,old_size; size = (i2f(Total_countdown_time)-Countdown_timer) / fl2f(0.65); old_size = (i2f(Total_countdown_time)-old_time) / fl2f(0.65); if (size != old_size && (Countdown_seconds_left < (Total_countdown_time-5) )) { // Every 2 seconds! //@@if (Dead_controlcen_object_num != -1) { //@@ vms_vector vp; //,v,c; //@@ compute_segment_center(&vp, &Segments[Objects[Dead_controlcen_object_num].segnum]); //@@ object_create_explosion( Objects[Dead_controlcen_object_num].segnum, &vp, size*10, VCLIP_SMALL_EXPLOSION); //@@} digi_play_sample( SOUND_CONTROL_CENTER_WARNING_SIREN, F3_0 ); } } else { int flash_value; if (old_time > 0) digi_play_sample( SOUND_MINE_BLEW_UP, F1_0 ); flash_value = f2i(-Countdown_timer * (64 / 4)); // 4 seconds to total whiteness PALETTE_FLASH_SET(flash_value,flash_value,flash_value); if (PaletteBlueAdd > 64 ) { gr_set_current_canvas( NULL ); gr_clear_canvas(BM_XRGB(31,31,31)); //make screen all white to match palette effect reset_palette_add(); //restore palette for death message //controlcen->MaxCapacity = Fuelcen_max_amount; //gauge_message( "Control Center Reset" ); DoPlayerDead(); //kill_player(); } } } // ----------------------------------------------------------------------------- // Called when control center gets destroyed. // This code is common to whether control center is implicitly imbedded in a boss, // or is an object of its own. // if objp == NULL that means the boss was the control center and don't set Dead_controlcen_object_num void do_controlcen_destroyed_stuff(object *objp) { int i; // Must toggle walls whether it is a boss or control center. for (i=0;isegnum]; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know to deal with cloaked dudes. It // seems to work in single-player mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. #ifdef NETWORK if (Game_mode & GM_MULTI) Believed_player_pos = Objects[Players[Player_num].objnum].pos; #endif // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i=0; ichildren[i] != -1) break; if (i == MAX_SIDES_PER_SEGMENT) return; vm_vec_sub(&vec_to_player, &ConsoleObject->pos, &obj->pos); dist_to_player = vm_vec_normalize_quick(&vec_to_player); if (dist_to_player < F1_0*200) { Control_center_player_been_seen = player_is_visible_from_object(obj, &obj->pos, 0, &vec_to_player); Control_center_next_fire_time = 0; } } return; } if (Player_is_dead) controlcen_death_silence += FrameTime; else controlcen_death_silence = 0; if ((Control_center_next_fire_time < 0) && !(controlcen_death_silence > F1_0*2)) { reactor *reactor = get_reactor_definition(obj->id); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) best_gun_num = calc_best_gun(reactor->n_guns, obj, &Believed_player_pos); else best_gun_num = calc_best_gun(reactor->n_guns, obj, &ConsoleObject->pos); if (best_gun_num != -1) { vms_vector vec_to_goal; fix dist_to_player; fix delta_fire_time; if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { vm_vec_sub(&vec_to_goal, &Believed_player_pos, &obj->ctype.reactor_info.gun_pos[best_gun_num]); dist_to_player = vm_vec_normalize_quick(&vec_to_goal); } else { vm_vec_sub(&vec_to_goal, &ConsoleObject->pos, &obj->ctype.reactor_info.gun_pos[best_gun_num]); dist_to_player = vm_vec_normalize_quick(&vec_to_goal); } if (dist_to_player > F1_0*300) { Control_center_been_hit = 0; Control_center_player_been_seen = 0; return; } #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects); #endif Laser_create_new_easy( &vec_to_goal, &obj->ctype.reactor_info.gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1); // 1/4 of time, fire another thing, not directly at player, so it might hit him if he's constantly moving. if (d_rand() < 32767/4) { vms_vector randvec; make_random_vector(&randvec); vm_vec_scale_add2(&vec_to_goal, &randvec, F1_0/4); vm_vec_normalize_quick(&vec_to_goal); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects); #endif Laser_create_new_easy( &vec_to_goal, &obj->ctype.reactor_info.gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1); } delta_fire_time = (NDL - Difficulty_level) * F1_0/4; #ifdef NETWORK if (Game_mode & GM_MULTI) // slow down rate of fire in multi player delta_fire_time *= 2; #endif Control_center_next_fire_time = delta_fire_time; } } else Control_center_next_fire_time -= FrameTime; } // ----------------------------------------------------------------------------- // This must be called at the start of each level. // If this level contains a boss and mode != multiplayer, don't do control center stuff. (Ghost out control center object.) // If this level contains a boss and mode == multiplayer, do control center stuff. void init_controlcen_for_level(void) { int i; object *objp; int cntrlcen_objnum=-1, boss_objnum=-1; for (i=0; i<=Highest_object_index; i++) { objp = &Objects[i]; if (objp->type == OBJ_CNTRLCEN) { if (cntrlcen_objnum != -1) ; else cntrlcen_objnum = i; } if ((objp->type == OBJ_ROBOT) && (Robot_info[objp->id].boss_flag)) { if (boss_objnum != -1) ; else boss_objnum = i; } } #ifndef NDEBUG if (cntrlcen_objnum == -1) { Dead_controlcen_object_num = -1; return; } #endif #ifdef NETWORK if ( (boss_objnum != -1) && !((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_ROBOTS)) ) #else if (boss_objnum != -1) #endif { if (cntrlcen_objnum != -1) { // note link to above!!! Objects[cntrlcen_objnum].type = OBJ_GHOST; Objects[cntrlcen_objnum].render_type = RT_NONE; Control_center_present = 0; } } else if (cntrlcen_objnum != -1) { // Compute all gun positions. objp = &Objects[cntrlcen_objnum]; reactor *reactor = get_reactor_definition(objp->id); for (i=0; in_guns; i++) calc_controlcen_gun_point(reactor, objp, i); Control_center_present = 1; // Boost control center strength at higher levels. if (Current_level_num >= 0) objp->shields = F1_0*200 + (F1_0*200/4) * Current_level_num; else objp->shields = F1_0*200 - Current_level_num*F1_0*100; } // Say the control center has not yet been hit. Control_center_been_hit = 0; Control_center_player_been_seen = 0; Control_center_next_fire_time = 0; Dead_controlcen_object_num = -1; } /* * reads a control_center_triggers structure from a PHYSFS_file */ extern int control_center_triggers_read_n(control_center_triggers *cct, int n, PHYSFS_file *fp) { int i, j; for (i = 0; i < n; i++) { cct->num_links = PHYSFSX_readShort(fp); for (j = 0; j < MAX_WALLS_PER_LINK; j++) cct->seg[j] = PHYSFSX_readShort(fp); for (j = 0; j < MAX_WALLS_PER_LINK; j++) cct->side[j] = PHYSFSX_readShort(fp); } return i; } void control_center_triggers_swap(control_center_triggers *cct, int swap) { int i; if (!swap) return; cct->num_links = SWAPSHORT(cct->num_links); for (i = 0; i < MAX_WALLS_PER_LINK; i++) cct->seg[i] = SWAPSHORT(cct->seg[i]); for (i = 0; i < MAX_WALLS_PER_LINK; i++) cct->side[i] = SWAPSHORT(cct->side[i]); } /* * reads n control_center_triggers structs from a PHYSFS_file and swaps if specified */ void control_center_triggers_read_n_swap(control_center_triggers *cct, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, cct, sizeof(control_center_triggers), n); if (swap) for (i = 0; i < n; i++) control_center_triggers_swap(&cct[i], swap); } int control_center_triggers_write(control_center_triggers *cct, PHYSFS_file *fp) { int j; PHYSFS_writeSLE16(fp, cct->num_links); for (j = 0; j < MAX_CONTROLCEN_LINKS; j++) PHYSFS_writeSLE16(fp, cct->seg[j]); for (j = 0; j < MAX_CONTROLCEN_LINKS; j++) PHYSFS_writeSLE16(fp, cct->side[j]); return 1; } dxx-rebirth-0.58.1-d1x/main/cntrlcen.h000066400000000000000000000053361217717257200174660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for cntrlcen.c * */ #ifndef _CNTRLCEN_H #define _CNTRLCEN_H #include "vecmat.h" #include "object.h" #include "wall.h" #include "switch.h" #define CONTROLCEN_WEAPON_NUM 6 #define MAX_CONTROLCEN_LINKS 10 typedef struct control_center_triggers { short num_links; short seg[MAX_CONTROLCEN_LINKS]; short side[MAX_CONTROLCEN_LINKS]; } __pack__ control_center_triggers; extern control_center_triggers ControlCenterTriggers; typedef struct reactor { int n_guns; vms_vector gun_points[MAX_CONTROLCEN_GUNS]; vms_vector gun_dirs[MAX_CONTROLCEN_GUNS]; } reactor; #define MAX_REACTORS 1 extern reactor Reactors[MAX_REACTORS]; static inline int get_num_reactor_models() { return 1; } static inline int get_reactor_model_number(int id) { return id; } static inline reactor *get_reactor_definition(int id) { (void)id; return &Reactors[0]; } extern int Control_center_been_hit; extern int Control_center_player_been_seen; extern int Control_center_next_fire_time; extern int Control_center_present; extern int Dead_controlcen_object_num; // do whatever this thing does in a frame extern void do_controlcen_frame(object *obj); // Initialize control center for a level. // Call when a new level is started. extern void init_controlcen_for_level(void); extern void calc_controlcen_gun_point(reactor *reactor, object *obj,int gun_num); extern void do_controlcen_destroyed_stuff(object *objp); extern void do_controlcen_dead_frame(void); extern fix Countdown_timer; extern int Control_center_destroyed, Countdown_seconds_left, Total_countdown_time; /* * reads n control_center_triggers structs from a PHYSFS_file */ extern int control_center_triggers_read_n(control_center_triggers *cct, int n, PHYSFS_file *fp); /* * reads n control_center_triggers structs from a PHYSFS_file and swaps if specified */ void control_center_triggers_read_n_swap(control_center_triggers *cct, int n, int swap, PHYSFS_file *fp); extern int control_center_triggers_write(control_center_triggers *cct, PHYSFS_file *fp); #endif dxx-rebirth-0.58.1-d1x/main/collide.c000066400000000000000000001561051217717257200172650ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to handle collisions * */ #include // for memset #include #include #include "rle.h" #include "inferno.h" #include "game.h" #include "gr.h" #include "stdlib.h" #include "bm.h" #include "3d.h" #include "segment.h" #include "texmap.h" #include "laser.h" #include "key.h" #include "gameseg.h" #include "object.h" #include "physics.h" #include "slew.h" #include "wall.h" #include "vclip.h" #include "polyobj.h" #include "fireball.h" #include "laser.h" #include "dxxerror.h" #include "ai.h" #include "hostage.h" #include "fuelcen.h" #include "sounds.h" #include "robot.h" #include "weapon.h" #include "player.h" #include "gauges.h" #include "powerup.h" #include "newmenu.h" #include "scores.h" #include "effects.h" #include "textures.h" #include "multi.h" #include "cntrlcen.h" #include "newdemo.h" #include "endlevel.h" #include "multibot.h" #include "piggy.h" #include "text.h" #include "maths.h" #ifdef EDITOR #include "editor/editor.h" #endif #include "collide.h" #define WALL_DAMAGE_SCALE (128) // Was 32 before 8:55 am on Thursday, September 15, changed by MK, walls were hurting me more than robots! #define WALL_DAMAGE_THRESHOLD (F1_0/3) #define WALL_LOUDNESS_SCALE (20) #define FORCE_DAMAGE_THRESHOLD (F1_0/3) #define STANDARD_EXPL_DELAY (F1_0/4) int check_collision_delayfunc_exec() { static fix64 last_play_time=0; if (last_play_time + (F1_0/3) < GameTime64 || last_play_time > GameTime64) { last_play_time = GameTime64; last_play_time -= (d_rand()/2); // add some randomness return 1; } return 0; } // ------------------------------------------------------------------------------------------------------------- // The only reason this routine is called (as of 10/12/94) is so Brain guys can open doors. void collide_robot_and_wall( object * robot, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { if ((robot->id == ROBOT_BRAIN) || (robot->ctype.ai_info.behavior == AIB_RUN_FROM)) { int wall_num = Segments[hitseg].sides[hitwall].wall_num; if (wall_num != -1) { if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].keys == KEY_NONE) && (Walls[wall_num].state == WALL_DOOR_CLOSED) && !(Walls[wall_num].flags & WALL_DOOR_LOCKED)) { wall_open_door(&Segments[hitseg], hitwall); } } } return; } //##void collide_hostage_and_wall( object * hostage, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { //## return; //##} // ------------------------------------------------------------------------------------------------------------- int apply_damage_to_clutter(object *clutter, fix damage) { if ( clutter->flags&OF_EXPLODING) return 0; if (clutter->shields < 0 ) return 0; //clutter already dead... clutter->shields -= damage; if (clutter->shields < 0) { explode_object(clutter,0); return 1; } else return 0; } //given the specified force, apply damage from that force to an object void apply_force_damage(object *obj,fix force,object *other_obj) { int result; fix damage; if (obj->flags & (OF_EXPLODING|OF_SHOULD_BE_DEAD)) return; //already exploding or dead damage = fixdiv(force,obj->mtype.phys_info.mass) / 8; if (damage < FORCE_DAMAGE_THRESHOLD) return; switch (obj->type) { case OBJ_ROBOT: if (Robot_info[obj->id].attack_type == 1) { if (other_obj->type == OBJ_WEAPON) result = apply_damage_to_robot(obj,damage/4, other_obj->ctype.laser_info.parent_num); else result = apply_damage_to_robot(obj,damage/4, other_obj-Objects); } else { if (other_obj->type == OBJ_WEAPON) result = apply_damage_to_robot(obj,damage/2, other_obj->ctype.laser_info.parent_num); else result = apply_damage_to_robot(obj,damage/2, other_obj-Objects); } if (result && (other_obj->ctype.laser_info.parent_signature == ConsoleObject->signature)) add_points_to_score(Robot_info[obj->id].score_value); break; case OBJ_PLAYER: // If colliding with a claw type robot, do damage proportional to FrameTime because you can collide with those // bots every frame since they don't move. if ( (other_obj->type == OBJ_ROBOT) && (Robot_info[other_obj->id].attack_type) ) damage = fixmul(damage, FrameTime*2); apply_damage_to_player(obj,other_obj,damage,0); break; case OBJ_CLUTTER: apply_damage_to_clutter(obj,damage); break; case OBJ_CNTRLCEN: // Never hits! Reactor does not have MT_PHYSICS - it's stationary! So no force damage here. apply_damage_to_controlcen(obj,damage, other_obj-Objects); break; case OBJ_WEAPON: break; //weapons don't take damage default: Int3(); } } // ----------------------------------------------------------------------------- void bump_this_object(object *objp, object *other_objp, vms_vector *force, int damage_flag) { fix force_mag; if (! (objp->mtype.phys_info.flags & PF_PERSISTENT)) { if (objp->type == OBJ_PLAYER) { vms_vector force2; force2.x = force->x/4; force2.y = force->y/4; force2.z = force->z/4; phys_apply_force(objp,&force2); if (damage_flag) { force_mag = vm_vec_mag_quick(&force2); apply_force_damage(objp, force_mag, other_objp); } } else if ((objp->type == OBJ_ROBOT) || (objp->type == OBJ_CLUTTER) || (objp->type == OBJ_CNTRLCEN)) { if (!Robot_info[objp->id].boss_flag) { vms_vector force2; force2.x = force->x/(4 + Difficulty_level); force2.y = force->y/(4 + Difficulty_level); force2.z = force->z/(4 + Difficulty_level); phys_apply_force(objp, force); phys_apply_rot(objp, &force2); if (damage_flag) { force_mag = vm_vec_mag_quick(force); apply_force_damage(objp, force_mag, other_objp); } } } } } // ----------------------------------------------------------------------------- //deal with two objects bumping into each other. Apply force from collision //to each robot. The flags tells whether the objects should take damage from //the collision. void bump_two_objects(object *obj0,object *obj1,int damage_flag) { vms_vector force; object *t=NULL; vm_vec_zero(&force); if (obj0->movement_type != MT_PHYSICS) t=obj1; else if (obj1->movement_type != MT_PHYSICS) t=obj0; if (t) { Assert(t->movement_type == MT_PHYSICS); vm_vec_copy_scale(&force,&t->mtype.phys_info.velocity,-t->mtype.phys_info.mass); phys_apply_force(t,&force); return; } vm_vec_sub(&force,&obj0->mtype.phys_info.velocity,&obj1->mtype.phys_info.velocity); vm_vec_scale2(&force,2*fixmul(obj0->mtype.phys_info.mass,obj1->mtype.phys_info.mass),(obj0->mtype.phys_info.mass+obj1->mtype.phys_info.mass)); bump_this_object(obj1, obj0, &force, damage_flag); vm_vec_negate(&force); bump_this_object(obj0, obj1, &force, damage_flag); } void bump_one_object(object *obj0, vms_vector *hit_dir, fix damage) { vms_vector hit_vec; hit_vec = *hit_dir; vm_vec_scale(&hit_vec, damage); phys_apply_force(obj0,&hit_vec); } void collide_player_and_wall( object * player, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { fix damage; if (player->id != Player_num) // Execute only for local player return; // If this wall does damage, don't make *BONK* sound, we'll be making another sound. if (TmapInfo[Segments[hitseg].sides[hitwall].tmap_num].damage > 0) return; wall_hit_process( &Segments[hitseg], hitwall, 20, player->id, player ); // ** Damage from hitting wall ** // If the player has less than 10% shields, don't take damage from bump damage = hitspeed / WALL_DAMAGE_SCALE; if (damage >= WALL_DAMAGE_THRESHOLD) { int volume; volume = (hitspeed-(WALL_DAMAGE_SCALE*WALL_DAMAGE_THRESHOLD)) / WALL_LOUDNESS_SCALE ; create_awareness_event(player, PA_WEAPON_WALL_COLLISION); if ( volume > F1_0 ) volume = F1_0; if (volume > 0 ) { digi_link_sound_to_pos( SOUND_PLAYER_HIT_WALL, hitseg, 0, hitpt, 0, volume ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_PLAYER_HIT_WALL, volume); #endif } if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) if ( Players[Player_num].shields > f1_0*10 ) apply_damage_to_player( player, player, damage, 0 ); } return; } fix64 Last_volatile_scrape_sound_time = 0; void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt); void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt); //this gets called when an object is scraping along the wall void scrape_player_on_wall(object *obj, short hitseg, short hitside, vms_vector * hitpt ) { fix d; if (obj->type != OBJ_PLAYER || obj->id != Player_num) return; if ((d=TmapInfo[Segments[hitseg].sides[hitside].tmap_num].damage) > 0) { vms_vector hit_dir, rand_vec; fix damage = fixmul(d,FrameTime); if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) apply_damage_to_player( obj, obj, damage, 0 ); PALETTE_FLASH_ADD(f2i(damage*4), 0, 0); //flash red if ((GameTime64 > Last_volatile_scrape_sound_time + F1_0/4) || (GameTime64 < Last_volatile_scrape_sound_time)) { Last_volatile_scrape_sound_time = GameTime64; digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HISS,hitseg, 0, hitpt, 0, F1_0 ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_VOLATILE_WALL_HISS, F1_0); #endif } #ifdef COMPACT_SEGS get_side_normal(&Segments[hitseg], hitside, 0, &hit_dir ); #else hit_dir = Segments[hitseg].sides[hitside].normals[0]; #endif make_random_vector(&rand_vec); vm_vec_scale_add2(&hit_dir, &rand_vec, F1_0/8); vm_vec_normalize_quick(&hit_dir); bump_one_object(obj, &hit_dir, F1_0*8); obj->mtype.phys_info.rotvel.x = (d_rand() - 16384)/2; obj->mtype.phys_info.rotvel.z = (d_rand() - 16384)/2; } } //if an effect is hit, and it can blow up, then blow it up //returns true if it blew up int check_effect_blowup(segment *seg,int side,vms_vector *pnt) { int tm,ec,db; if ((tm=seg->sides[side].tmap_num2) != 0) if ((ec=TmapInfo[tm&0x3fff].eclip_num)!=-1) if ((db=Effects[ec].dest_bm_num)!=-1 && !(Effects[ec].flags&EF_ONE_SHOT)) { fix u,v; grs_bitmap *bm = &GameBitmaps[Textures[tm&0x3fff].index]; int x,y,t; PIGGY_PAGE_IN(Textures[tm&0x3fff]); //this can be blown up...did we hit it? find_hitpoint_uv(&u,&v,NULL,pnt,seg,side,0); //evil: always say face zero x = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w; y = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h; switch (tm&0xc000) { //adjust for orientation of paste-on case 0x0000: break; case 0x4000: t=y; y=x; x=bm->bm_w-t-1; break; case 0x8000: y=bm->bm_h-y-1; x=bm->bm_w-x-1; break; case 0xc000: t=x; x=y; y=bm->bm_h-t-1; break; } if (bm->bm_flags & BM_FLAG_RLE) bm = rle_expand_texture(bm); if (gr_gpixel (bm, x, y) != 255) { //not trans, thus on effect int vc,sound_num; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_effect_blowup( seg-Segments, side, pnt); vc = Effects[ec].dest_vclip; object_create_explosion( seg-Segments, pnt, Effects[ec].dest_size, vc ); if ((sound_num = Vclip[vc].sound_num) != -1) digi_link_sound_to_pos( sound_num, seg-Segments, 0, pnt, 0, F1_0 ); if ((sound_num=Effects[ec].sound_num)!=-1) //kill sound digi_kill_sound_linked_to_segment(seg-Segments,side,sound_num); if (Effects[ec].dest_eclip!=-1 && Effects[Effects[ec].dest_eclip].segnum==-1) { int bm_num; eclip *new_ec; new_ec = &Effects[Effects[ec].dest_eclip]; bm_num = new_ec->changing_wall_texture; new_ec->time_left = new_ec->vc.frame_time; new_ec->frame_count = 0; new_ec->segnum = seg-Segments; new_ec->sidenum = side; new_ec->flags |= EF_ONE_SHOT; new_ec->dest_bm_num = Effects[ec].dest_bm_num; Assert(bm_num!=0 && seg->sides[side].tmap_num2!=0); seg->sides[side].tmap_num2 = bm_num | (tm&0xc000); //replace with destoyed } else { Assert(db!=0 && seg->sides[side].tmap_num2!=0); seg->sides[side].tmap_num2 = db | (tm&0xc000); //replace with destoyed } return 1; //blew up! } } return 0; //didn't blow up } //these gets added to the weapon's values when the weapon hits a volitle wall #define VOLATILE_WALL_EXPL_STRENGTH i2f(10) #define VOLATILE_WALL_IMPACT_SIZE i2f(3) #define VOLATILE_WALL_DAMAGE_FORCE i2f(5) #define VOLATILE_WALL_DAMAGE_RADIUS i2f(30) // int Show_seg_and_side = 0; void collide_weapon_and_wall( object * weapon, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { segment *seg = &Segments[hitseg]; int blew_up; int wall_type; int playernum; if (weapon->mtype.phys_info.flags & PF_BOUNCE) return; if ((weapon->mtype.phys_info.velocity.x == 0) && (weapon->mtype.phys_info.velocity.y == 0) && (weapon->mtype.phys_info.velocity.z == 0)) { Int3(); // Contact Matt: This is impossible. A weapon with 0 velocity hit a wall, which doesn't move. return; } blew_up = check_effect_blowup(seg,hitwall,hitpt); //if ((seg->sides[hitwall].tmap_num2==0) && (TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE)) { if (Objects[weapon->ctype.laser_info.parent_num].type == OBJ_PLAYER) playernum = Objects[weapon->ctype.laser_info.parent_num].id; else playernum = -1; //not a player wall_type = wall_hit_process( seg, hitwall, weapon->shields, playernum, weapon ); // Wall is volatile if either tmap 1 or 2 is volatile if ((TmapInfo[seg->sides[hitwall].tmap_num].flags & TMI_VOLATILE) || (seg->sides[hitwall].tmap_num2 && (TmapInfo[seg->sides[hitwall].tmap_num2&0x3fff].flags & TMI_VOLATILE))) { weapon_info *wi = &Weapon_info[weapon->id]; //we've hit a volatile wall digi_link_sound_to_pos( SOUND_VOLATILE_WALL_HIT,hitseg, 0, hitpt, 0, F1_0 ); object_create_badass_explosion( weapon, hitseg, hitpt, wi->impact_size + VOLATILE_WALL_IMPACT_SIZE, VCLIP_VOLATILE_WALL_HIT, wi->strength[Difficulty_level]/4+VOLATILE_WALL_EXPL_STRENGTH, // diminished by mk on 12/08/94, i was doing 70 damage hitting lava on lvl 1. wi->damage_radius+VOLATILE_WALL_DAMAGE_RADIUS, wi->strength[Difficulty_level]/2+VOLATILE_WALL_DAMAGE_FORCE, weapon->ctype.laser_info.parent_num ); weapon->flags |= OF_SHOULD_BE_DEAD; //make flares die in lava } else { //if it's not the player's weapon, or it is the player's and there //is no wall, and no blowing up monitor, then play sound if ((weapon->ctype.laser_info.parent_type != OBJ_PLAYER) || ((seg->sides[hitwall].wall_num == -1 || wall_type==WHP_NOT_SPECIAL) && !blew_up)) if ((Weapon_info[weapon->id].wall_hit_sound > -1 ) && (!(weapon->flags & OF_SILENT))) digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound,weapon->segnum, 0, &weapon->pos, 0, F1_0 ); if ( Weapon_info[weapon->id].wall_hit_vclip > -1 ) { if ( Weapon_info[weapon->id].damage_radius ) explode_badass_weapon(weapon); else object_create_explosion( weapon->segnum, &weapon->pos, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].wall_hit_vclip ); } } if ( weapon->ctype.laser_info.parent_type== OBJ_PLAYER ) { if (!(weapon->flags & OF_SILENT) && (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum)) create_awareness_event(weapon, PA_WEAPON_WALL_COLLISION); // object "weapon" can attract attention to player // if (weapon->id != FLARE_ID) { // We now allow flares to open doors. { if (weapon->id != FLARE_ID) weapon->flags |= OF_SHOULD_BE_DEAD; if (!(weapon->flags & OF_SILENT)) { switch (wall_type) { case WHP_NOT_SPECIAL: //should be handled above //digi_link_sound_to_pos( Weapon_info[weapon->id].wall_hit_sound, weapon->segnum, 0, &weapon->pos, 0, F1_0 ); break; case WHP_NO_KEY: //play special hit door sound (if/when we get it) digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, weapon->segnum, 0, &weapon->pos, 0, F1_0 ); break; case WHP_BLASTABLE: //play special blastable wall sound (if/when we get it) digi_link_sound_to_pos( SOUND_WEAPON_HIT_BLASTABLE, weapon->segnum, 0, &weapon->pos, 0, F1_0 ); break; case WHP_DOOR: //don't play anything, since door open sound will play break; } } // else } // else { // if (weapon->lifeleft <= 0) // weapon->flags |= OF_SHOULD_BE_DEAD; // } } else { // This is a robot's laser weapon->flags |= OF_SHOULD_BE_DEAD; } return; } //##void collide_camera_and_wall( object * camera, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { //## return; //##} //##void collide_powerup_and_wall( object * powerup, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { //## return; //##} void collide_debris_and_wall( object * debris, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt) { if (!PERSISTENT_DEBRIS || TmapInfo[Segments[hitseg].sides[hitwall].tmap_num].damage) explode_object(debris,0); return; } //##void collide_fireball_and_fireball( object * fireball1, object * fireball2, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_robot( object * fireball, object * robot, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_hostage( object * fireball, object * hostage, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_player( object * fireball, object * player, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_weapon( object * fireball, object * weapon, vms_vector *collision_point ) { //## //weapon->flags |= OF_SHOULD_BE_DEAD; //## return; //##} //##void collide_fireball_and_camera( object * fireball, object * camera, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_powerup( object * fireball, object * powerup, vms_vector *collision_point ) { //## return; //##} //##void collide_fireball_and_debris( object * fireball, object * debris, vms_vector *collision_point ) { //## return; //##} // ------------------------------------------------------------------------------------------------------------------- void collide_robot_and_robot( object * robot1, object * robot2, vms_vector *collision_point ) { bump_two_objects(robot1, robot2, 1); return; } void collide_robot_and_controlcen( object * obj1, object * obj2, vms_vector *collision_point ) { if (obj1->type == OBJ_ROBOT) { vms_vector hitvec; vm_vec_normalize(vm_vec_sub(&hitvec, &obj2->pos, &obj1->pos)); bump_one_object(obj1, &hitvec, 0); } else { vms_vector hitvec; vm_vec_normalize(vm_vec_sub(&hitvec, &obj1->pos, &obj2->pos)); bump_one_object(obj2, &hitvec, 0); } } //##void collide_robot_and_hostage( object * robot, object * hostage, vms_vector *collision_point ) { //## return; //##} void collide_robot_and_player( object * robot, object * player, vms_vector *collision_point ) { if (player->id == Player_num) { create_awareness_event(player, PA_PLAYER_COLLISION); // object robot can attract attention to player do_ai_robot_hit_attack(robot, player, collision_point); do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION); } #ifdef NETWORK #ifndef SHAREWARE else { multi_robot_request_change(robot, player->id); return; // only controlling player should make damage otherwise we might juggle robot back and forth, killing it instantly } #endif #endif if (check_collision_delayfunc_exec()) { int collision_seg = find_point_seg(collision_point, player->segnum); digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 ); if (collision_seg != -1) object_create_explosion( collision_seg, collision_point, Weapon_info[0].impact_size, Weapon_info[0].wall_hit_vclip ); } bump_two_objects(robot, player, 1); return; } // Provide a way for network message to instantly destroy the control center // without awarding points or anything. // if controlcen == NULL, that means don't do the explosion because the control center // was actually in another object. void net_destroy_controlcen(object *controlcen) { if (Control_center_destroyed != 1) { do_controlcen_destroyed_stuff(controlcen); if ((controlcen != NULL) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED))) { digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 ); explode_object(controlcen,0); } } } // ----------------------------------------------------------------------------- void apply_damage_to_controlcen(object *controlcen, fix damage, short who) { int whotype; // Only allow a player to damage the control center. if ((who < 0) || (who > Highest_object_index)) return; whotype = Objects[who].type; if (whotype != OBJ_PLAYER) { return; } #ifdef NETWORK #ifndef SHAREWARE if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) && ((i2f(Players[Player_num].hours_level*3600)+Players[Player_num].time_level) < Netgame.control_invul_time)) { if (Objects[who].id == Player_num) { int secs = f2i(Netgame.control_invul_time-(i2f(Players[Player_num].hours_level*3600)+Players[Player_num].time_level)) % 60; int mins = f2i(Netgame.control_invul_time-(i2f(Players[Player_num].hours_level*3600)+Players[Player_num].time_level)) / 60; HUD_init_message(HM_DEFAULT, "%s %d:%02d.", TXT_CNTRLCEN_INVUL, mins, secs); } return; } #endif #endif if (Objects[who].id == Player_num) { Control_center_been_hit = 1; ai_do_cloak_stuff(); } if ( controlcen->shields >= 0 ) controlcen->shields -= damage; if ( (controlcen->shields < 0) && !(controlcen->flags&(OF_EXPLODING|OF_DESTROYED)) ) { do_controlcen_destroyed_stuff(controlcen); #ifdef NETWORK if (Game_mode & GM_MULTI) { if (who == Players[Player_num].objnum) add_points_to_score(CONTROL_CEN_SCORE); multi_send_destroy_controlcen((ushort)(controlcen-Objects), Objects[who].id ); } #endif if (!(Game_mode & GM_MULTI)) add_points_to_score(CONTROL_CEN_SCORE); digi_link_sound_to_pos( SOUND_CONTROL_CENTER_DESTROYED, controlcen->segnum, 0, &controlcen->pos, 0, F1_0 ); explode_object(controlcen,0); } } void collide_player_and_controlcen( object * controlcen, object * player, vms_vector *collision_point ) { if (player->id == Player_num) { Control_center_been_hit = 1; ai_do_cloak_stuff(); // In case player cloaked, make control center know where he is. } if (check_collision_delayfunc_exec()) digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 ); bump_two_objects(controlcen, player, 1); return; } // If a persistent weapon and other object is not a weapon, weaken it, else kill it. // If both objects are weapons, weaken the weapon. void maybe_kill_weapon(object *weapon, object *other_obj) { if (is_proximity_bomb_or_smart_mine(weapon->id)) { weapon->flags |= OF_SHOULD_BE_DEAD; return; } if ((weapon->mtype.phys_info.flags & PF_PERSISTENT) || (other_obj->type == OBJ_WEAPON)) { // Weapons do a lot of damage to weapons, other objects do much less. if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) { if (other_obj->type == OBJ_WEAPON) weapon->shields -= other_obj->shields/2; else weapon->shields -= other_obj->shields/4; if (weapon->shields <= 0) { weapon->shields = 0; weapon->flags |= OF_SHOULD_BE_DEAD; } } } else weapon->flags |= OF_SHOULD_BE_DEAD; } void collide_weapon_and_controlcen( object * weapon, object *controlcen, vms_vector *collision_point ) { if (weapon->ctype.laser_info.parent_type == OBJ_PLAYER) { fix damage = weapon->shields; /* * Check if persistent weapon already hit this object. If yes, abort. * If no, add this object to hitobj_list and do it's damage. */ if (weapon->mtype.phys_info.flags & PF_PERSISTENT) { damage = weapon->shields*2; // to not alter Gameplay too much, multiply damage by 2. if (!weapon->ctype.laser_info.hitobj_list[controlcen-Objects]) { weapon->ctype.laser_info.hitobj_list[controlcen-Objects] = 1; weapon->ctype.laser_info.last_hitobj = controlcen-Objects; } else { return; } } if (Objects[weapon->ctype.laser_info.parent_num].id == Player_num) Control_center_been_hit = 1; if ( Weapon_info[weapon->id].damage_radius ) explode_badass_weapon(weapon); else object_create_explosion( controlcen->segnum, collision_point, ((controlcen->size/3)*3)/4, VCLIP_SMALL_EXPLOSION ); digi_link_sound_to_pos( SOUND_CONTROL_CENTER_HIT, controlcen->segnum, 0, collision_point, 0, F1_0 ); damage = fixmul(damage, weapon->ctype.laser_info.multiplier); apply_damage_to_controlcen(controlcen, damage, weapon->ctype.laser_info.parent_num); maybe_kill_weapon(weapon,controlcen); } else { // If robot weapon hits control center, blow it up, make it go away, but do no damage to control center. object_create_explosion( controlcen->segnum, collision_point, ((controlcen->size/3)*3)/4, VCLIP_SMALL_EXPLOSION ); maybe_kill_weapon(weapon,controlcen); } } void collide_weapon_and_clutter( object * weapon, object *clutter, vms_vector *collision_point ) { short exp_vclip = VCLIP_SMALL_EXPLOSION; if ( clutter->shields >= 0 ) clutter->shields -= weapon->shields; digi_link_sound_to_pos( SOUND_LASER_HIT_CLUTTER, weapon->segnum, 0, collision_point, 0, F1_0 ); object_create_explosion( clutter->segnum, collision_point, ((clutter->size/3)*3)/4, exp_vclip ); if ( (clutter->shields < 0) && !(clutter->flags&(OF_EXPLODING|OF_DESTROYED))) explode_object(clutter,STANDARD_EXPL_DELAY); maybe_kill_weapon(weapon,clutter); } //--mk, 121094 -- extern void spin_robot(object *robot, vms_vector *collision_point); // ------------------------------------------------------------------------------------------------------ // Return 1 if robot died, else return 0 int apply_damage_to_robot(object *robot, fix damage, int killer_objnum) { if ( robot->flags&OF_EXPLODING) return 0; if (robot->shields < 0 ) return 0; //robot already dead... // if (robot->control_type == CT_REMOTE) // return 0; // Can't damange a robot controlled by another player if (Robot_info[robot->id].boss_flag) Boss_been_hit = 1; robot->shields -= damage; if (robot->shields < 0) { #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) { if (multi_explode_robot_sub(robot-Objects, killer_objnum, 0)) { multi_send_robot_explode(robot-Objects, killer_objnum, 0); return 1; } else return 0; } #endif #endif Players[Player_num].num_kills_level++; Players[Player_num].num_kills_total++; if (Robot_info[robot->id].boss_flag) { start_boss_death_sequence(robot); //do_controlcen_destroyed_stuff(NULL); } else explode_object(robot,STANDARD_EXPL_DELAY); return 1; } else return 0; } // ------------------------------------------------------------------------------------------------------ void collide_robot_and_weapon( object * robot, object * weapon, vms_vector *collision_point ) { if (Robot_info[robot->id].boss_flag) Boss_hit_this_frame = 1; #if 1 /* * Check if persistent weapon already hit this object. If yes, abort. * If no, add this object to hitobj_list and do it's damage. */ if (weapon->mtype.phys_info.flags & PF_PERSISTENT) { if (!weapon->ctype.laser_info.hitobj_list[robot-Objects]) { weapon->ctype.laser_info.hitobj_list[robot-Objects] = 1; weapon->ctype.laser_info.last_hitobj = robot-Objects; } else { return; } } #else // If a persistent weapon hit robot most recently, quick abort, else we cream the same robot many times, // depending on frame rate. if (weapon->mtype.phys_info.flags & PF_PERSISTENT) { if (weapon->ctype.laser_info.last_hitobj == robot-Objects) return; else weapon->ctype.laser_info.last_hitobj = robot-Objects; } #endif if (weapon->ctype.laser_info.parent_signature == robot->signature) return; if ( Weapon_info[weapon->id].damage_radius ) explode_badass_weapon(weapon); if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(robot->flags & OF_EXPLODING) ) { object *expl_obj=NULL; if (weapon->ctype.laser_info.parent_num == Players[Player_num].objnum) { create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION); // object "weapon" can attract attention to player do_ai_robot_hit(robot, PA_WEAPON_ROBOT_COLLISION); } #ifdef NETWORK #ifndef SHAREWARE else multi_robot_request_change(robot, Objects[weapon->ctype.laser_info.parent_num].id); #endif #endif //--mk, 121094 -- spin_robot(robot, collision_point); if ( Robot_info[robot->id].exp1_vclip_num > -1 ) expl_obj = object_create_explosion( weapon->segnum, collision_point, (robot->size/2*3)/4, Robot_info[robot->id].exp1_vclip_num ); //NOT_USED else if ( Weapon_info[weapon->id].robot_hit_vclip > -1 ) //NOT_USED expl_obj = object_create_explosion( weapon->segnum, collision_point, Weapon_info[weapon->id].impact_size, Weapon_info[weapon->id].robot_hit_vclip ); if (expl_obj) obj_attach(robot,expl_obj); if ( Robot_info[robot->id].exp1_sound_num > -1 ) digi_link_sound_to_pos( Robot_info[robot->id].exp1_sound_num, robot->segnum, 0, collision_point, 0, F1_0 ); if (!(weapon->flags & OF_HARMLESS)) { fix damage = weapon->shields; damage = fixmul(damage, weapon->ctype.laser_info.multiplier); if (! apply_damage_to_robot(robot, damage, weapon->ctype.laser_info.parent_num)) bump_two_objects(robot, weapon, 0); //only bump if not dead. no damage from bump else if (weapon->ctype.laser_info.parent_signature == ConsoleObject->signature) add_points_to_score(Robot_info[robot->id].score_value); } } maybe_kill_weapon(weapon,robot); return; } //##void collide_robot_and_camera( object * robot, object * camera, vms_vector *collision_point ) { //## return; //##} //##void collide_robot_and_powerup( object * robot, object * powerup, vms_vector *collision_point ) { //## return; //##} //##void collide_robot_and_debris( object * robot, object * debris, vms_vector *collision_point ) { //## return; //##} //##void collide_hostage_and_hostage( object * hostage1, object * hostage2, vms_vector *collision_point ) { //## return; //##} void collide_hostage_and_player( object * hostage, object * player, vms_vector *collision_point ) { // Give player points, etc. if ( player == ConsoleObject ) { add_points_to_score(HOSTAGE_SCORE); // Do effect hostage_rescue(hostage->id); // Remove the hostage object. hostage->flags |= OF_SHOULD_BE_DEAD; #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_remobj(hostage-Objects); #endif } return; } //--unused-- void collide_hostage_and_weapon( object * hostage, object * weapon, vms_vector *collision_point ) //--unused-- { //--unused-- // Cannot kill hostages, as per Matt's edict! //--unused-- // (A fine edict, but in contradiction to the milestone: "Robots attack hostages.") //--unused-- hostage->shields -= weapon->shields/2; //--unused-- //--unused-- create_awareness_event(weapon, PA_WEAPON_ROBOT_COLLISION); // object "weapon" can attract attention to player //--unused-- //--unused-- //PLAY_SOUND_3D( SOUND_HOSTAGE_KILLED, collision_point, hostage->segnum ); //--unused-- digi_link_sound_to_pos( SOUND_HOSTAGE_KILLED, hostage->segnum , 0, collision_point, 0, F1_0 ); //--unused-- //--unused-- //--unused-- if (hostage->shields <= 0) { //--unused-- explode_object(hostage,0); //--unused-- hostage->flags |= OF_SHOULD_BE_DEAD; //--unused-- } //--unused-- //--unused-- if ( Weapon_info[weapon->id].damage_radius ) //--unused-- explode_badass_weapon(weapon); //--unused-- //--unused-- maybe_kill_weapon(weapon,hostage); //--unused-- //--unused-- } //##void collide_hostage_and_camera( object * hostage, object * camera, vms_vector *collision_point ) { //## return; //##} //##void collide_hostage_and_powerup( object * hostage, object * powerup, vms_vector *collision_point ) { //## return; //##} //##void collide_hostage_and_debris( object * hostage, object * debris, vms_vector *collision_point ) { //## return; //##} void collide_player_and_player( object * player1, object * player2, vms_vector *collision_point ) { static fix64 last_player_bump[MAX_PLAYERS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int damage_flag = 1, otherpl = -1; if (check_collision_delayfunc_exec()) digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player1->segnum, 0, collision_point, 0, F1_0 ); // Multi is special - as always. Clients do the bump damage locally but the remote players do their collision result (change velocity) on their own. So after our initial collision, ignore further collision damage till remote players (hopefully) react. if (Game_mode & GM_MULTI) { damage_flag = 0; if (!(player1->id == Player_num || player2->id == Player_num)) return; if (player1->id > MAX_PLAYERS || player2->id > MAX_PLAYERS) return; otherpl = (player1->id==Player_num)?player2->id:player1->id; if (last_player_bump[otherpl] + (F1_0/Netgame.PacketsPerSec) < GameTime64 || last_player_bump[otherpl] > GameTime64) { last_player_bump[otherpl] = GameTime64; damage_flag = 1; } } bump_two_objects(player1, player2, damage_flag); return; } int maybe_drop_primary_weapon_egg(object *playerobj, int weapon_index) { int weapon_flag = HAS_FLAG(weapon_index); int powerup_num; powerup_num = Primary_weapon_to_powerup[weapon_index]; if (Players[playerobj->id].primary_weapon_flags & weapon_flag) return call_object_create_egg(playerobj, 1, OBJ_POWERUP, powerup_num); else return -1; } void maybe_drop_secondary_weapon_egg(object *playerobj, int weapon_index, int count) { int weapon_flag = HAS_FLAG(weapon_index); int powerup_num; powerup_num = Secondary_weapon_to_powerup[weapon_index]; if (Players[playerobj->id].secondary_weapon_flags & weapon_flag) { int i, max_count; max_count = min(count, 3); for (i=0; iid].secondary_ammo[missile_index]; powerup_id = Secondary_weapon_to_powerup[missile_index]; if (num_missiles > 10) num_missiles = 10; call_object_create_egg(playerobj, num_missiles/4, OBJ_POWERUP, powerup_id+1); call_object_create_egg(playerobj, num_missiles%4, OBJ_POWERUP, powerup_id); } void drop_player_eggs(object *playerobj) { if ((playerobj->type == OBJ_PLAYER) || (playerobj->type == OBJ_GHOST)) { int pnum = playerobj->id; int objnum; int vulcan_ammo=0; // Seed the random number generator so in net play the eggs will always // drop the same way #ifdef NETWORK if (Game_mode & GM_MULTI) { Net_create_loc = 0; d_srand(5483L); } #endif // If the player dies and he has powerful lasers, create the powerups here. if (Players[pnum].laser_level >= 1) call_object_create_egg(playerobj, Players[pnum].laser_level, OBJ_POWERUP, POW_LASER); // Note: laser_level = 0 for laser level 1. // Drop quad laser if appropos if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS) call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_QUAD_FIRE); if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED) call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_CLOAK); //Drop the vulcan, gauss, and ammo vulcan_ammo = Players[pnum].primary_ammo[VULCAN_INDEX]; if (vulcan_ammo < VULCAN_AMMO_AMOUNT) vulcan_ammo = VULCAN_AMMO_AMOUNT; //make sure gun has at least as much as a powerup objnum = maybe_drop_primary_weapon_egg(playerobj, VULCAN_INDEX); if (objnum!=-1) Objects[objnum].ctype.powerup_info.count = vulcan_ammo; // Drop the rest of the primary weapons maybe_drop_primary_weapon_egg(playerobj, SPREADFIRE_INDEX); maybe_drop_primary_weapon_egg(playerobj, PLASMA_INDEX); maybe_drop_primary_weapon_egg(playerobj, FUSION_INDEX); // Drop the secondary weapons // Note, proximity weapon only comes in packets of 4. So drop n/2, but a max of 3 (handled inside maybe_drop..) Make sense? maybe_drop_secondary_weapon_egg(playerobj, PROXIMITY_INDEX, (Players[playerobj->id].secondary_ammo[PROXIMITY_INDEX])/4); maybe_drop_secondary_weapon_egg(playerobj, SMART_INDEX, Players[playerobj->id].secondary_ammo[SMART_INDEX]); maybe_drop_secondary_weapon_egg(playerobj, MEGA_INDEX, Players[playerobj->id].secondary_ammo[MEGA_INDEX]); // Drop the player's missiles in packs of 1 and/or 4 drop_missile_1_or_4(playerobj,HOMING_INDEX); drop_missile_1_or_4(playerobj,CONCUSSION_INDEX); // If player has vulcan ammo, but no vulcan cannon, drop the ammo. if (!(Players[playerobj->id].primary_weapon_flags & HAS_VULCAN_FLAG)) { int amount = Players[playerobj->id].primary_ammo[VULCAN_INDEX]; if (amount > 200) { amount = 200; } while (amount > 0) { call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_VULCAN_AMMO); amount -= VULCAN_AMMO_AMOUNT; } } // Always drop a shield and energy powerup. if (Game_mode & GM_MULTI) { call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_SHIELD_BOOST); call_object_create_egg(playerobj, 1, OBJ_POWERUP, POW_ENERGY); } } } void apply_damage_to_player(object *player, object *killer, fix damage, ubyte possibly_friendly) { if (Player_is_dead) return; if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) return; if (multi_maybe_disable_friendly_fire(killer) && possibly_friendly) return; if (Endlevel_sequence) return; //for the player, the 'real' shields are maintained in the Players[] //array. The shields value in the player's object are, I think, not //used anywhere. This routine, however, sets the objects shields to //be a mirror of the value in the Player structure. if (player->id == Player_num) { //is this the local player? Players[Player_num].shields -= damage; PALETTE_FLASH_ADD(f2i(damage)*4,-f2i(damage/2),-f2i(damage/2)); //flash red if (Players[Player_num].shields < 0) { Players[Player_num].killer_objnum = killer-Objects; // if ( killer && (killer->type == OBJ_PLAYER)) // Players[Player_num].killer_objnum = killer-Objects; player->flags |= OF_SHOULD_BE_DEAD; } player->shields = Players[Player_num].shields; //mirror } } void collide_player_and_weapon( object * player, object * weapon, vms_vector *collision_point ) { fix damage = weapon->shields; object * killer=NULL; damage = fixmul(damage, weapon->ctype.laser_info.multiplier); #if 1 /* * Check if persistent weapon already hit this object. If yes, abort. * If no, add this object to hitobj_list and do it's damage. */ if (weapon->mtype.phys_info.flags & PF_PERSISTENT) { if (!weapon->ctype.laser_info.hitobj_list[player-Objects]) { weapon->ctype.laser_info.hitobj_list[player-Objects] = 1; weapon->ctype.laser_info.last_hitobj = player-Objects; } else { return; } } #else if (weapon->mtype.phys_info.flags & PF_PERSISTENT) { if (weapon->ctype.laser_info.last_hitobj == player-Objects) return; else weapon->ctype.laser_info.last_hitobj = player-Objects; } #endif if (player->id == Player_num) { if (!(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) { digi_link_sound_to_pos( SOUND_PLAYER_GOT_HIT, player->segnum, 0, collision_point, 0, F1_0 ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_PLAYER_GOT_HIT, F1_0); #endif } else { digi_link_sound_to_pos( SOUND_WEAPON_HIT_DOOR, player->segnum, 0, collision_point, 0, F1_0); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_WEAPON_HIT_DOOR, F1_0); #endif } } object_create_explosion( player->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT ); if ( Weapon_info[weapon->id].damage_radius ) explode_badass_weapon(weapon); maybe_kill_weapon(weapon,player); bump_two_objects(player, weapon, 0); //no damage from bump if ( !Weapon_info[weapon->id].damage_radius ) { if ( weapon->ctype.laser_info.parent_num > -1 ) killer = &Objects[weapon->ctype.laser_info.parent_num]; // if (weapon->id == SMART_HOMING_ID) // damage /= 4; if (!(weapon->flags & OF_HARMLESS)) apply_damage_to_player( player, killer, damage, 1); } // Robots become aware of you if you get hit. ai_do_cloak_stuff(); return; } // Nasty robots are the ones that attack you by running into you and doing lots of damage. void collide_player_and_nasty_robot( object * player, object * robot, vms_vector *collision_point ) { digi_link_sound_to_pos( Robot_info[robot->id].claw_sound, player->segnum, 0, collision_point, 0, F1_0 ); object_create_explosion( player->segnum, collision_point, i2f(10)/2, VCLIP_PLAYER_HIT ); bump_two_objects(player, robot, 0); //no damage from bump apply_damage_to_player( player, robot, F1_0*(Difficulty_level+1), 0); return; } void collide_player_and_materialization_center(object *objp) { int side; vms_vector exit_dir; segment *segp = &Segments[objp->segnum]; digi_link_sound_to_pos(SOUND_PLAYER_GOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0); // digi_play_sample( SOUND_PLAYER_GOT_HIT, F1_0 ); object_create_explosion( objp->segnum, &objp->pos, i2f(10)/2, VCLIP_PLAYER_HIT ); if (objp->id != Player_num) return; for (side=0; sidepos); vm_vec_normalize_quick(&exit_dir); make_random_vector(&rand_vec); rand_vec.x /= 4; rand_vec.y /= 4; rand_vec.z /= 4; vm_vec_add2(&exit_dir, &rand_vec); vm_vec_normalize_quick(&exit_dir); } bump_one_object(objp, &exit_dir, 64*F1_0); apply_damage_to_player( objp, NULL, 4*F1_0, 0); return; } void collide_robot_and_materialization_center(object *objp) { int side; vms_vector exit_dir; segment *segp=&Segments[objp->segnum]; vm_vec_zero(&exit_dir); digi_link_sound_to_pos(SOUND_ROBOT_HIT, objp->segnum, 0, &objp->pos, 0, F1_0); if ( Robot_info[objp->id].exp1_vclip_num > -1 ) object_create_explosion( objp->segnum, &objp->pos, (objp->size/2*3)/4, Robot_info[objp->id].exp1_vclip_num ); for (side=0; sidepos); vm_vec_normalize_quick(&exit_dir); } bump_one_object(objp, &exit_dir, 8*F1_0); apply_damage_to_robot( objp, F1_0, -1); return; } //##void collide_player_and_camera( object * player, object * camera, vms_vector *collision_point ) { //## return; //##} extern int Network_got_powerup; // HACK!!! void collide_player_and_powerup( object * player, object * powerup, vms_vector *collision_point ) { if (!Endlevel_sequence && !Player_is_dead && (player->id == Player_num )) { int powerup_used; powerup_used = do_powerup(powerup); if (powerup_used) { powerup->flags |= OF_SHOULD_BE_DEAD; #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_remobj(powerup-Objects); #endif } } #ifndef SHAREWARE else if ((Game_mode & GM_MULTI_COOP) && (player->id != Player_num)) { switch (powerup->id) { case POW_KEY_BLUE: Players[player->id].flags |= PLAYER_FLAGS_BLUE_KEY; break; case POW_KEY_RED: Players[player->id].flags |= PLAYER_FLAGS_RED_KEY; break; case POW_KEY_GOLD: Players[player->id].flags |= PLAYER_FLAGS_GOLD_KEY; break; default: break; } } #endif return; } //##void collide_player_and_debris( object * player, object * debris, vms_vector *collision_point ) { //## return; //##} void collide_player_and_clutter( object * player, object * clutter, vms_vector *collision_point ) { if (check_collision_delayfunc_exec()) digi_link_sound_to_pos( SOUND_ROBOT_HIT_PLAYER, player->segnum, 0, collision_point, 0, F1_0 ); bump_two_objects(clutter, player, 1); return; } // See if weapon1 creates a badass explosion. If so, create the explosion // Return true if weapon does proximity (as opposed to only contact) damage when it explodes. int maybe_detonate_weapon(object *weapon1, object *weapon2, vms_vector *collision_point) { if ( Weapon_info[weapon1->id].damage_radius ) { fix dist; dist = vm_vec_dist_quick(&weapon1->pos, &weapon2->pos); if (dist < F1_0*5) { maybe_kill_weapon(weapon1,weapon2); if (weapon1->flags & OF_SHOULD_BE_DEAD) { explode_badass_weapon(weapon1); digi_link_sound_to_pos( Weapon_info[weapon1->id].robot_hit_sound, weapon1->segnum , 0, collision_point, 0, F1_0 ); } return 1; } else { weapon1->lifeleft = min(dist/64, F1_0); return 1; } } else return 0; } void collide_weapon_and_weapon( object * weapon1, object * weapon2, vms_vector *collision_point ) { if ((Weapon_info[weapon1->id].destroyable) || (Weapon_info[weapon2->id].destroyable)) { // shooting Plasma will make bombs explode one drops at the same time since hitboxes overlap. Small HACK to get around this issue. if the player moves away from the bomb at least... if ((GameTime64 < weapon1->ctype.laser_info.creation_time + (F1_0/5)) && (GameTime64 < weapon2->ctype.laser_info.creation_time + (F1_0/5)) && (weapon1->ctype.laser_info.parent_num == weapon2->ctype.laser_info.parent_num)) return; // Bug reported by Adam Q. Pletcher on September 9, 1994, smart bomb homing missiles were toasting each other. if ((weapon1->id == weapon2->id) && (weapon1->ctype.laser_info.parent_num == weapon2->ctype.laser_info.parent_num)) return; if (Weapon_info[weapon1->id].destroyable) if (maybe_detonate_weapon(weapon1, weapon2, collision_point)) maybe_kill_weapon(weapon2,weapon1); if (Weapon_info[weapon2->id].destroyable) if (maybe_detonate_weapon(weapon2, weapon1, collision_point)) maybe_kill_weapon(weapon1,weapon2); } } //##void collide_weapon_and_camera( object * weapon, object * camera, vms_vector *collision_point ) { //## return; //##} //##void collide_weapon_and_powerup( object * weapon, object * powerup, vms_vector *collision_point ) { //## return; //##} void collide_weapon_and_debris( object * weapon, object * debris, vms_vector *collision_point ) { if ( (weapon->ctype.laser_info.parent_type==OBJ_PLAYER) && !(debris->flags & OF_EXPLODING) ) { digi_link_sound_to_pos( SOUND_ROBOT_HIT, weapon->segnum , 0, collision_point, 0, F1_0 ); explode_object(debris,0); if ( Weapon_info[weapon->id].damage_radius ) explode_badass_weapon(weapon); maybe_kill_weapon(weapon,debris); if (!(weapon->mtype.phys_info.flags & PF_PERSISTENT)) weapon->flags |= OF_SHOULD_BE_DEAD; } return; } //##void collide_camera_and_camera( object * camera1, object * camera2, vms_vector *collision_point ) { //## return; //##} //##void collide_camera_and_powerup( object * camera, object * powerup, vms_vector *collision_point ) { //## return; //##} //##void collide_camera_and_debris( object * camera, object * debris, vms_vector *collision_point ) { //## return; //##} //##void collide_powerup_and_powerup( object * powerup1, object * powerup2, vms_vector *collision_point ) { //## return; //##} //##void collide_powerup_and_debris( object * powerup, object * debris, vms_vector *collision_point ) { //## return; //##} //##void collide_debris_and_debris( object * debris1, object * debris2, vms_vector *collision_point ) { //## return; //##} #define COLLISION_OF(a,b) (((a)<<8) + (b)) // DPH: Put these macros on one long line to avoid CR/LF problems under Linux. #define DO_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type2) ): (collision_function)( (A), (B), collision_point ); break; case COLLISION_OF( (type2), (type1) ): (collision_function)( (B), (A), collision_point ); break; #define DO_SAME_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type1) ): (collision_function)( (A), (B), collision_point ); break; //these next two macros define a case that does nothing #define NO_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type2) ): case COLLISION_OF( (type2), (type1) ): break; #define NO_SAME_COLLISION(type1,type2,collision_function) case COLLISION_OF( (type1), (type1) ): break; // DPH: These ones are never used so I'm not going to bother. #ifndef __LINUX__ #define IGNORE_COLLISION(type1,type2,collision_function) \ case COLLISION_OF( (type1), (type2) ): \ break; \ case COLLISION_OF( (type2), (type1) ): \ break; #define ERROR_COLLISION(type1,type2,collision_function) \ case COLLISION_OF( (type1), (type2) ): \ Error( "Error in collision type!" ); \ break; \ case COLLISION_OF( (type2), (type1) ): \ Error( "Error in collision type!" ); \ break; #endif void collide_two_objects( object * A, object * B, vms_vector *collision_point ) { int collision_type; collision_type = COLLISION_OF(A->type,B->type); switch( collision_type ) { NO_SAME_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL, collide_fireball_and_fireball ) DO_SAME_COLLISION( OBJ_ROBOT, OBJ_ROBOT, collide_robot_and_robot ) NO_SAME_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE, collide_hostage_and_hostage ) DO_SAME_COLLISION( OBJ_PLAYER, OBJ_PLAYER, collide_player_and_player ) DO_SAME_COLLISION( OBJ_WEAPON, OBJ_WEAPON, collide_weapon_and_weapon ) NO_SAME_COLLISION( OBJ_CAMERA, OBJ_CAMERA, collide_camera_and_camera ) NO_SAME_COLLISION( OBJ_POWERUP, OBJ_POWERUP, collide_powerup_and_powerup ) NO_SAME_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS, collide_debris_and_debris ) NO_COLLISION( OBJ_FIREBALL, OBJ_ROBOT, collide_fireball_and_robot ) NO_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE, collide_fireball_and_hostage ) NO_COLLISION( OBJ_FIREBALL, OBJ_PLAYER, collide_fireball_and_player ) NO_COLLISION( OBJ_FIREBALL, OBJ_WEAPON, collide_fireball_and_weapon ) NO_COLLISION( OBJ_FIREBALL, OBJ_CAMERA, collide_fireball_and_camera ) NO_COLLISION( OBJ_FIREBALL, OBJ_POWERUP, collide_fireball_and_powerup ) NO_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS, collide_fireball_and_debris ) NO_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE, collide_robot_and_hostage ) DO_COLLISION( OBJ_ROBOT, OBJ_PLAYER, collide_robot_and_player ) DO_COLLISION( OBJ_ROBOT, OBJ_WEAPON, collide_robot_and_weapon ) NO_COLLISION( OBJ_ROBOT, OBJ_CAMERA, collide_robot_and_camera ) NO_COLLISION( OBJ_ROBOT, OBJ_POWERUP, collide_robot_and_powerup ) NO_COLLISION( OBJ_ROBOT, OBJ_DEBRIS, collide_robot_and_debris ) DO_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER, collide_hostage_and_player ) NO_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON, collide_hostage_and_weapon ) NO_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA, collide_hostage_and_camera ) NO_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP, collide_hostage_and_powerup ) NO_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS, collide_hostage_and_debris ) DO_COLLISION( OBJ_PLAYER, OBJ_WEAPON, collide_player_and_weapon ) NO_COLLISION( OBJ_PLAYER, OBJ_CAMERA, collide_player_and_camera ) DO_COLLISION( OBJ_PLAYER, OBJ_POWERUP, collide_player_and_powerup ) NO_COLLISION( OBJ_PLAYER, OBJ_DEBRIS, collide_player_and_debris ) DO_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN, collide_player_and_controlcen ) DO_COLLISION( OBJ_PLAYER, OBJ_CLUTTER, collide_player_and_clutter ) NO_COLLISION( OBJ_WEAPON, OBJ_CAMERA, collide_weapon_and_camera ) NO_COLLISION( OBJ_WEAPON, OBJ_POWERUP, collide_weapon_and_powerup ) DO_COLLISION( OBJ_WEAPON, OBJ_DEBRIS, collide_weapon_and_debris ) NO_COLLISION( OBJ_CAMERA, OBJ_POWERUP, collide_camera_and_powerup ) NO_COLLISION( OBJ_CAMERA, OBJ_DEBRIS, collide_camera_and_debris ) NO_COLLISION( OBJ_POWERUP, OBJ_DEBRIS, collide_powerup_and_debris ) DO_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN, collide_weapon_and_controlcen ) DO_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN, collide_robot_and_controlcen ) DO_COLLISION( OBJ_WEAPON, OBJ_CLUTTER, collide_weapon_and_clutter ) default: Int3(); //Error( "Unhandled collision_type in collide.c!\n" ); } } #define ENABLE_COLLISION(type1,type2) CollisionResult[type1][type2] = RESULT_CHECK; CollisionResult[type2][type1] = RESULT_CHECK; #define DISABLE_COLLISION(type1,type2) CollisionResult[type1][type2] = RESULT_NOTHING; CollisionResult[type2][type1] = RESULT_NOTHING; void collide_init() { int i, j; for (i=0; i < MAX_OBJECT_TYPES; i++ ) for (j=0; j < MAX_OBJECT_TYPES; j++ ) CollisionResult[i][j] = RESULT_NOTHING; ENABLE_COLLISION( OBJ_WALL, OBJ_ROBOT ); ENABLE_COLLISION( OBJ_WALL, OBJ_WEAPON ); ENABLE_COLLISION( OBJ_WALL, OBJ_PLAYER ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_FIREBALL ); ENABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT ); // DISABLE_COLLISION( OBJ_ROBOT, OBJ_ROBOT ); // ALERT: WARNING: HACK: MK = RESPONSIBLE! TESTING!! DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_HOSTAGE ); ENABLE_COLLISION( OBJ_PLAYER, OBJ_PLAYER ); ENABLE_COLLISION( OBJ_WEAPON, OBJ_WEAPON ); DISABLE_COLLISION( OBJ_CAMERA, OBJ_CAMERA ); DISABLE_COLLISION( OBJ_POWERUP, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_DEBRIS, OBJ_DEBRIS ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_ROBOT ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_HOSTAGE ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_PLAYER ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_WEAPON ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_CAMERA ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_FIREBALL, OBJ_DEBRIS ); DISABLE_COLLISION( OBJ_ROBOT, OBJ_HOSTAGE ); ENABLE_COLLISION( OBJ_ROBOT, OBJ_PLAYER ); ENABLE_COLLISION( OBJ_ROBOT, OBJ_WEAPON ); DISABLE_COLLISION( OBJ_ROBOT, OBJ_CAMERA ); DISABLE_COLLISION( OBJ_ROBOT, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_ROBOT, OBJ_DEBRIS ); ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_PLAYER ); ENABLE_COLLISION( OBJ_HOSTAGE, OBJ_WEAPON ); DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_CAMERA ); DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_HOSTAGE, OBJ_DEBRIS ); ENABLE_COLLISION( OBJ_PLAYER, OBJ_WEAPON ); DISABLE_COLLISION( OBJ_PLAYER, OBJ_CAMERA ); ENABLE_COLLISION( OBJ_PLAYER, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_PLAYER, OBJ_DEBRIS ); DISABLE_COLLISION( OBJ_WEAPON, OBJ_CAMERA ); DISABLE_COLLISION( OBJ_WEAPON, OBJ_POWERUP ); ENABLE_COLLISION( OBJ_WEAPON, OBJ_DEBRIS ); DISABLE_COLLISION( OBJ_CAMERA, OBJ_POWERUP ); DISABLE_COLLISION( OBJ_CAMERA, OBJ_DEBRIS ); DISABLE_COLLISION( OBJ_POWERUP, OBJ_DEBRIS ); ENABLE_COLLISION( OBJ_POWERUP, OBJ_WALL ); ENABLE_COLLISION( OBJ_WEAPON, OBJ_CNTRLCEN ) ENABLE_COLLISION( OBJ_WEAPON, OBJ_CLUTTER ) ENABLE_COLLISION( OBJ_PLAYER, OBJ_CNTRLCEN ) ENABLE_COLLISION( OBJ_ROBOT, OBJ_CNTRLCEN ) ENABLE_COLLISION( OBJ_PLAYER, OBJ_CLUTTER ) ENABLE_COLLISION( OBJ_DEBRIS, OBJ_WALL ); } void collide_object_with_wall( object * A, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt ) { switch( A->type ) { case OBJ_NONE: Error( "A object of type NONE hit a wall!\n"); break; case OBJ_PLAYER: collide_player_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break; case OBJ_WEAPON: collide_weapon_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break; case OBJ_DEBRIS: collide_debris_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break; case OBJ_FIREBALL: break; //collide_fireball_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_ROBOT: collide_robot_and_wall(A,hitspeed,hitseg,hitwall,hitpt); break; case OBJ_HOSTAGE: break; //collide_hostage_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_CAMERA: break; //collide_camera_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_POWERUP: break; //collide_powerup_and_wall(A,hitspeed,hitseg,hitwall,hitpt); case OBJ_GHOST: break; //do nothing default: Error( "Unhandled object type hit wall in collide.c\n" ); } } dxx-rebirth-0.58.1-d1x/main/collide.h000066400000000000000000000044231217717257200172650ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * Header for collide.c * */ #ifndef _COLLIDE_H #define _COLLIDE_H #include "playsave.h" void collide_init(); void collide_two_objects(object * A, object * B, vms_vector *collision_point); void collide_object_with_wall(object * A, fix hitspeed, short hitseg, short hitwall, vms_vector * hitpt); extern void apply_damage_to_player(object *player, object *killer, fix damage, ubyte possibly_friendly); // Returns 1 if robot died, else 0. extern int apply_damage_to_robot(object *robot, fix damage, int killer_objnum); extern int Immaterial; #define PERSISTENT_DEBRIS (PlayerCfg.PersistentDebris && !(Game_mode & GM_MULTI)) // no persistent debris in multi extern void collide_player_and_weapon(object * player, object * weapon, vms_vector *collision_point); extern void collide_player_and_materialization_center(object *objp); extern void collide_robot_and_materialization_center(object *objp); extern void scrape_player_on_wall(object *obj, short hitseg, short hitwall, vms_vector * hitpt); extern int maybe_detonate_weapon(object *obj0p, object *obj, vms_vector *pos); extern void collide_player_and_nasty_robot(object * player, object * robot, vms_vector *collision_point); extern void net_destroy_controlcen(object *controlcen); extern void collide_player_and_powerup(object * player, object * powerup, vms_vector *collision_point); extern int check_effect_blowup(segment *seg,int side,vms_vector *pnt); extern void apply_damage_to_controlcen(object *controlcen, fix damage, short who); extern void bump_one_object(object *obj0, vms_vector *hit_dir, fix damage); #endif dxx-rebirth-0.58.1-d1x/main/config.c000066400000000000000000000261331217717257200171140ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * contains routine(s) to read in the configuration file which contains * game configuration stuff like detail level, sound card, etc * */ #include #include #include #include #include "config.h" #include "pstypes.h" #include "game.h" #include "songs.h" #include "kconfig.h" #include "palette.h" #include "args.h" #include "player.h" #include "mission.h" #include "physfsx.h" struct Cfg GameCfg; static const char DigiVolumeStr[] = "DigiVolume"; static const char MusicVolumeStr[] = "MusicVolume"; static const char ReverseStereoStr[] = "ReverseStereo"; static const char OrigTrackOrderStr[] = "OrigTrackOrder"; static const char MusicTypeStr[] = "MusicType"; static const char CMLevelMusicPlayOrderStr[] = "CMLevelMusicPlayOrder"; static const char CMLevelMusicTrack0Str[] = "CMLevelMusicTrack0"; static const char CMLevelMusicTrack1Str[] = "CMLevelMusicTrack1"; static const char CMLevelMusicPathStr[] = "CMLevelMusicPath"; static const char CMMiscMusic0Str[] = "CMMiscMusic0"; static const char CMMiscMusic1Str[] = "CMMiscMusic1"; static const char CMMiscMusic2Str[] ="CMMiscMusic2"; static const char CMMiscMusic3Str[] = "CMMiscMusic3"; static const char CMMiscMusic4Str[] = "CMMiscMusic4"; static const char GammaLevelStr[] = "GammaLevel"; static const char LastPlayerStr[] = "LastPlayer"; static const char LastMissionStr[] = "LastMission"; static const char ResolutionXStr[] ="ResolutionX"; static const char ResolutionYStr[] ="ResolutionY"; static const char AspectXStr[] ="AspectX"; static const char AspectYStr[] ="AspectY"; static const char WindowModeStr[] ="WindowMode"; static const char TexFiltStr[] ="TexFilt"; static const char VSyncStr[] ="VSync"; static const char MultisampleStr[] ="Multisample"; static const char FPSIndicatorStr[] ="FPSIndicator"; static const char GrabinputStr[] ="GrabInput"; int ReadConfigFile() { PHYSFS_file *infile; char *line, *token, *value, *ptr; // set defaults GameCfg.DigiVolume = 8; GameCfg.MusicVolume = 8; GameCfg.ReverseStereo = 0; GameCfg.OrigTrackOrder = 0; #if defined(__APPLE__) && defined(__MACH__) GameCfg.MusicType = MUSIC_TYPE_REDBOOK; #else GameCfg.MusicType = MUSIC_TYPE_BUILTIN; #endif GameCfg.CMLevelMusicPlayOrder = MUSIC_CM_PLAYORDER_CONT; GameCfg.CMLevelMusicTrack[0] = -1; GameCfg.CMLevelMusicTrack[1] = -1; memset(GameCfg.CMLevelMusicPath,0,PATH_MAX+1); memset(GameCfg.CMMiscMusic[SONG_TITLE],0,PATH_MAX+1); memset(GameCfg.CMMiscMusic[SONG_BRIEFING],0,PATH_MAX+1); memset(GameCfg.CMMiscMusic[SONG_ENDLEVEL],0,PATH_MAX+1); memset(GameCfg.CMMiscMusic[SONG_ENDGAME],0,PATH_MAX+1); memset(GameCfg.CMMiscMusic[SONG_CREDITS],0,PATH_MAX+1); #if defined(__APPLE__) && defined(__MACH__) GameCfg.OrigTrackOrder = 1; GameCfg.CMLevelMusicPlayOrder = MUSIC_CM_PLAYORDER_LEVEL; snprintf(GameCfg.CMLevelMusicPath, PATH_MAX, "%s", "descent.m3u"); snprintf(GameCfg.CMMiscMusic[SONG_TITLE], PATH_MAX, "%s%s", PHYSFS_getUserDir(), "Music/iTunes/iTunes Music/Insanity/Descent/02 Primitive Rage.mp3"); snprintf(GameCfg.CMMiscMusic[SONG_BRIEFING], PATH_MAX, "%s%s", PHYSFS_getUserDir(), "Music/iTunes/iTunes Music/Insanity/Descent/03 Outerlimits.mp3"); snprintf(GameCfg.CMMiscMusic[SONG_ENDLEVEL], PATH_MAX, "%s%s", PHYSFS_getUserDir(), "Music/iTunes/iTunes Music/Insanity/Descent/04 Close Call.mp3"); snprintf(GameCfg.CMMiscMusic[SONG_ENDGAME], PATH_MAX, "%s%s", PHYSFS_getUserDir(), "Music/iTunes/iTunes Music/Insanity/Descent/14 Insanity.mp3"); snprintf(GameCfg.CMMiscMusic[SONG_CREDITS], PATH_MAX, "%s%s", PHYSFS_getUserDir(), "Music/iTunes/iTunes Music/Insanity/Descent/05 The Darkness Of Space.mp3"); #endif GameCfg.GammaLevel = 0; memset(GameCfg.LastPlayer,0,CALLSIGN_LEN+1); memset(GameCfg.LastMission,0,MISSION_NAME_LEN+1); GameCfg.ResolutionX = 640; GameCfg.ResolutionY = 480; GameCfg.AspectX = 3; GameCfg.AspectY = 4; GameCfg.WindowMode = 0; GameCfg.TexFilt = 0; GameCfg.VSync = 0; GameCfg.Multisample = 0; GameCfg.FPSIndicator = 0; GameCfg.Grabinput = 1; infile = PHYSFSX_openReadBuffered("descent.cfg"); if (infile == NULL) { return 1; } while (!PHYSFS_eof(infile)) { int max_len = PHYSFS_fileLength(infile); // to be fully safe, assume the whole cfg consists of one big line MALLOC(line, char, max_len); memset(line, 0, max_len); PHYSFSX_gets(infile, line); ptr = &(line[0]); while (isspace(*ptr)) ptr++; if (*ptr != '\0') { token = strtok(ptr, "="); value = strtok(NULL, "="); if (!value) value = ""; if (!strcmp(token, DigiVolumeStr)) GameCfg.DigiVolume = strtol(value, NULL, 10); else if (!strcmp(token, MusicVolumeStr)) GameCfg.MusicVolume = strtol(value, NULL, 10); else if (!strcmp(token, ReverseStereoStr)) GameCfg.ReverseStereo = strtol(value, NULL, 10); else if (!strcmp(token, OrigTrackOrderStr)) GameCfg.OrigTrackOrder = strtol(value, NULL, 10); else if (!strcmp(token, MusicTypeStr)) GameCfg.MusicType = strtol(value, NULL, 10); else if (!strcmp(token, CMLevelMusicPlayOrderStr)) GameCfg.CMLevelMusicPlayOrder = strtol(value, NULL, 10); else if (!strcmp(token, CMLevelMusicTrack0Str)) GameCfg.CMLevelMusicTrack[0] = strtol(value, NULL, 10); else if (!strcmp(token, CMLevelMusicTrack1Str)) GameCfg.CMLevelMusicTrack[1] = strtol(value, NULL, 10); else if (!strcmp(token, CMLevelMusicPathStr)) { char * p; strncpy( GameCfg.CMLevelMusicPath, value, PATH_MAX ); p = strchr( GameCfg.CMLevelMusicPath, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, CMMiscMusic0Str)) { char * p; strncpy( GameCfg.CMMiscMusic[SONG_TITLE], value, PATH_MAX ); p = strchr( GameCfg.CMMiscMusic[SONG_TITLE], '\n'); if ( p ) *p = 0; } else if (!strcmp(token, CMMiscMusic1Str)) { char * p; strncpy( GameCfg.CMMiscMusic[SONG_BRIEFING], value, PATH_MAX ); p = strchr( GameCfg.CMMiscMusic[SONG_BRIEFING], '\n'); if ( p ) *p = 0; } else if (!strcmp(token, CMMiscMusic2Str)) { char * p; strncpy( GameCfg.CMMiscMusic[SONG_ENDLEVEL], value, PATH_MAX ); p = strchr( GameCfg.CMMiscMusic[SONG_ENDLEVEL], '\n'); if ( p ) *p = 0; } else if (!strcmp(token, CMMiscMusic3Str)) { char * p; strncpy( GameCfg.CMMiscMusic[SONG_ENDGAME], value, PATH_MAX ); p = strchr( GameCfg.CMMiscMusic[SONG_ENDGAME], '\n'); if ( p ) *p = 0; } else if (!strcmp(token, CMMiscMusic4Str)) { char * p; strncpy( GameCfg.CMMiscMusic[SONG_CREDITS], value, PATH_MAX ); p = strchr( GameCfg.CMMiscMusic[SONG_CREDITS], '\n'); if ( p ) *p = 0; } else if (!strcmp(token, GammaLevelStr)) { GameCfg.GammaLevel = strtol(value, NULL, 10); gr_palette_set_gamma( GameCfg.GammaLevel ); } else if (!strcmp(token, LastPlayerStr)) { char * p; strncpy( GameCfg.LastPlayer, value, CALLSIGN_LEN ); p = strchr( GameCfg.LastPlayer, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, LastMissionStr)) { char * p; strncpy( GameCfg.LastMission, value, MISSION_NAME_LEN ); p = strchr( GameCfg.LastMission, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, ResolutionXStr)) GameCfg.ResolutionX = strtol(value, NULL, 10); else if (!strcmp(token, ResolutionYStr)) GameCfg.ResolutionY = strtol(value, NULL, 10); else if (!strcmp(token, AspectXStr)) GameCfg.AspectX = strtol(value, NULL, 10); else if (!strcmp(token, AspectYStr)) GameCfg.AspectY = strtol(value, NULL, 10); else if (!strcmp(token, WindowModeStr)) GameCfg.WindowMode = strtol(value, NULL, 10); else if (!strcmp(token, TexFiltStr)) GameCfg.TexFilt = strtol(value, NULL, 10); else if (!strcmp(token, VSyncStr)) GameCfg.VSync = strtol(value, NULL, 10); else if (!strcmp(token, MultisampleStr)) GameCfg.Multisample = strtol(value, NULL, 10); else if (!strcmp(token, FPSIndicatorStr)) GameCfg.FPSIndicator = strtol(value, NULL, 10); else if (!strcmp(token, GrabinputStr)) GameCfg.Grabinput = strtol(value, NULL, 10); } d_free(line); } PHYSFS_close(infile); if ( GameCfg.DigiVolume > 8 ) GameCfg.DigiVolume = 8; if ( GameCfg.MusicVolume > 8 ) GameCfg.MusicVolume = 8; if (GameCfg.ResolutionX >= 320 && GameCfg.ResolutionY >= 200) Game_screen_mode = SM(GameCfg.ResolutionX,GameCfg.ResolutionY); return 0; } int WriteConfigFile() { PHYSFS_file *infile; GameCfg.GammaLevel = gr_palette_get_gamma(); infile = PHYSFSX_openWriteBuffered("descent.cfg"); if (infile == NULL) { return 1; } PHYSFSX_printf(infile, "%s=%d\n", DigiVolumeStr, GameCfg.DigiVolume); PHYSFSX_printf(infile, "%s=%d\n", MusicVolumeStr, GameCfg.MusicVolume); PHYSFSX_printf(infile, "%s=%d\n", ReverseStereoStr, GameCfg.ReverseStereo); PHYSFSX_printf(infile, "%s=%d\n", OrigTrackOrderStr, GameCfg.OrigTrackOrder); PHYSFSX_printf(infile, "%s=%d\n", MusicTypeStr, GameCfg.MusicType); PHYSFSX_printf(infile, "%s=%d\n", CMLevelMusicPlayOrderStr, GameCfg.CMLevelMusicPlayOrder); PHYSFSX_printf(infile, "%s=%d\n", CMLevelMusicTrack0Str, GameCfg.CMLevelMusicTrack[0]); PHYSFSX_printf(infile, "%s=%d\n", CMLevelMusicTrack1Str, GameCfg.CMLevelMusicTrack[1]); PHYSFSX_printf(infile, "%s=%s\n", CMLevelMusicPathStr, GameCfg.CMLevelMusicPath); PHYSFSX_printf(infile, "%s=%s\n", CMMiscMusic0Str, GameCfg.CMMiscMusic[SONG_TITLE]); PHYSFSX_printf(infile, "%s=%s\n", CMMiscMusic1Str, GameCfg.CMMiscMusic[SONG_BRIEFING]); PHYSFSX_printf(infile, "%s=%s\n", CMMiscMusic2Str, GameCfg.CMMiscMusic[SONG_ENDLEVEL]); PHYSFSX_printf(infile, "%s=%s\n", CMMiscMusic3Str, GameCfg.CMMiscMusic[SONG_ENDGAME]); PHYSFSX_printf(infile, "%s=%s\n", CMMiscMusic4Str, GameCfg.CMMiscMusic[SONG_CREDITS]); PHYSFSX_printf(infile, "%s=%d\n", GammaLevelStr, GameCfg.GammaLevel); PHYSFSX_printf(infile, "%s=%s\n", LastPlayerStr, Players[Player_num].callsign); PHYSFSX_printf(infile, "%s=%s\n", LastMissionStr, GameCfg.LastMission); PHYSFSX_printf(infile, "%s=%i\n", ResolutionXStr, SM_W(Game_screen_mode)); PHYSFSX_printf(infile, "%s=%i\n", ResolutionYStr, SM_H(Game_screen_mode)); PHYSFSX_printf(infile, "%s=%i\n", AspectXStr, GameCfg.AspectX); PHYSFSX_printf(infile, "%s=%i\n", AspectYStr, GameCfg.AspectY); PHYSFSX_printf(infile, "%s=%i\n", WindowModeStr, GameCfg.WindowMode); PHYSFSX_printf(infile, "%s=%i\n", TexFiltStr, GameCfg.TexFilt); PHYSFSX_printf(infile, "%s=%i\n", VSyncStr, GameCfg.VSync); PHYSFSX_printf(infile, "%s=%i\n", MultisampleStr, GameCfg.Multisample); PHYSFSX_printf(infile, "%s=%i\n", FPSIndicatorStr, GameCfg.FPSIndicator); PHYSFSX_printf(infile, "%s=%i\n", GrabinputStr, GameCfg.Grabinput); PHYSFS_close(infile); return 0; } dxx-rebirth-0.58.1-d1x/main/config.h000066400000000000000000000032631217717257200171200ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * prototype definitions for descent.cfg reading/writing * */ #ifndef _CONFIG_H #define _CONFIG_H #include "player.h" #include "mission.h" typedef struct Cfg { ubyte DigiVolume; ubyte MusicVolume; int ReverseStereo; int OrigTrackOrder; int MusicType; int CMLevelMusicPlayOrder; int CMLevelMusicTrack[2]; char CMLevelMusicPath[PATH_MAX+1]; char CMMiscMusic[5][PATH_MAX+1]; int GammaLevel; char LastPlayer[CALLSIGN_LEN+1]; char LastMission[MISSION_NAME_LEN+1]; int ResolutionX; int ResolutionY; int AspectX; int AspectY; int WindowMode; int TexFilt; int VSync; int Multisample; int FPSIndicator; int Grabinput; } __pack__ Cfg; extern struct Cfg GameCfg; //#ifdef USE_SDLMIXER //#define EXT_MUSIC_ON (GameCfg.SndEnableRedbook || GameCfg.JukeboxOn) //#else //#define EXT_MUSIC_ON (GameCfg.SndEnableRedbook) // JukeboxOn shouldn't do anything if it's not supported //#endif extern int ReadConfigFile(void); extern int WriteConfigFile(void); #endif dxx-rebirth-0.58.1-d1x/main/console.c000066400000000000000000000140471217717257200173120ustar00rootroot00000000000000/* * * Game console * */ #include #include #include #include #include #include #include "window.h" #include "console.h" #include "args.h" #include "gr.h" #include "physfsx.h" #include "gamefont.h" #include "key.h" #include "vers_id.h" #include "timer.h" static PHYSFS_file *gamelog_fp=NULL; static struct console_buffer con_buffer[CON_LINES_MAX]; static int con_state = CON_STATE_CLOSED, con_scroll_offset = 0, con_size = 0; extern void game_flush_inputs(); static void con_add_buffer_line(int priority, char *buffer) { int i=0; /* shift con_buffer for one line */ for (i=1; itm_hour,lt->tm_min,lt->tm_sec); #ifdef _WIN32 // stupid hack to force DOS-style newlines if (buffer[strlen(buffer)-1] == '\n' && strlen(buffer) <= CON_LINE_LENGTH) { buffer[strlen(buffer)-1]='\r'; buffer[strlen(buffer)]='\n'; } #endif PHYSFSX_printf(gamelog_fp,"%s",buffer); } } } static void con_draw(void) { int i = 0, y = 0, done = 0; if (con_size <= 0) return; gr_set_current_canvas(NULL); gr_set_curfont(GAME_FONT); gr_setcolor(BM_XRGB(0,0,0)); gr_settransblend(7, GR_BLEND_NORMAL); gr_rect(0,0,SWIDTH,(LINE_SPACING*(con_size))+FSPACY(1)); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); y=FSPACY(1)+(LINE_SPACING*con_size); i+=con_scroll_offset; while (!done) { int w,h,aw; switch (con_buffer[CON_LINES_MAX-1-i].priority) { case CON_CRITICAL: gr_set_fontcolor(BM_XRGB(28,0,0),-1); break; case CON_URGENT: gr_set_fontcolor(BM_XRGB(54,54,0),-1); break; case CON_DEBUG: case CON_VERBOSE: gr_set_fontcolor(BM_XRGB(14,14,14),-1); break; case CON_HUD: gr_set_fontcolor(BM_XRGB(0,28,0),-1); break; default: gr_set_fontcolor(BM_XRGB(255,255,255),-1); break; } gr_get_string_size(con_buffer[CON_LINES_MAX-1-i].line,&w,&h,&aw); y-=h+FSPACY(1); gr_printf(FSPACX(1),y,"%s",con_buffer[CON_LINES_MAX-1-i].line); i++; if (y<=0 || CON_LINES_MAX-1-i <= 0 || i < 0) done=1; } gr_setcolor(BM_XRGB(0,0,0)); gr_rect(0,0,SWIDTH,LINE_SPACING); gr_set_fontcolor(BM_XRGB(255,255,255),-1); gr_printf(FSPACX(1),FSPACY(1),"%s LOG", DESCENT_VERSION); gr_printf(SWIDTH-FSPACX(110),FSPACY(1),"PAGE-UP/DOWN TO SCROLL"); } static int con_handler(window *wind, d_event *event) { int key; static fix64 last_scroll_time = 0; switch (event->type) { case EVENT_WINDOW_ACTIVATED: break; case EVENT_WINDOW_DEACTIVATED: con_size = 0; con_state = CON_STATE_CLOSED; break; case EVENT_KEY_COMMAND: key = event_key_get(event); switch (key) { case KEY_SHIFTED + KEY_ESC: switch (con_state) { case CON_STATE_OPEN: case CON_STATE_OPENING: con_state = CON_STATE_CLOSING; break; case CON_STATE_CLOSED: case CON_STATE_CLOSING: con_state = CON_STATE_OPENING; default: break; } break; case KEY_PAGEUP: con_scroll_offset+=CON_SCROLL_OFFSET; if (con_scroll_offset >= CON_LINES_MAX-1) con_scroll_offset = CON_LINES_MAX-1; while (con_buffer[CON_LINES_MAX-1-con_scroll_offset].line[0]=='\0') con_scroll_offset--; break; case KEY_PAGEDOWN: con_scroll_offset-=CON_SCROLL_OFFSET; if (con_scroll_offset<0) con_scroll_offset=0; break; default: break; } return 1; case EVENT_WINDOW_DRAW: timer_delay2(50); if (con_state == CON_STATE_OPENING) { if (con_size < CON_LINES_ONSCREEN && timer_query() >= last_scroll_time+(F1_0/30)) { last_scroll_time = timer_query(); con_size++; } } else if (con_state == CON_STATE_CLOSING) { if (con_size > 0 && timer_query() >= last_scroll_time+(F1_0/30)) { last_scroll_time = timer_query(); con_size--; } } if (con_size >= CON_LINES_ONSCREEN) con_state = CON_STATE_OPEN; else if (con_size <= 0) con_state = CON_STATE_CLOSED; if (con_state == CON_STATE_CLOSED && wind) window_close(wind); con_draw(); break; case EVENT_WINDOW_CLOSE: break; default: break; } return 0; } void con_showup(void) { window *wind; game_flush_inputs(); con_state = CON_STATE_OPENING; wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))con_handler, NULL); if (!wind) { d_event event = { EVENT_WINDOW_CLOSE }; con_handler(NULL, &event); return; } } static void con_close(void) { if (gamelog_fp) PHYSFS_close(gamelog_fp); gamelog_fp = NULL; } void con_init(void) { memset(con_buffer,0,sizeof(con_buffer)); if (GameArg.DbgSafelog) gamelog_fp = PHYSFS_openWrite("gamelog.txt"); else gamelog_fp = PHYSFSX_openWriteBuffered("gamelog.txt"); atexit(con_close); } dxx-rebirth-0.58.1-d1x/main/controls.c000066400000000000000000000070531217717257200175120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code for controlling player movement * */ #include #include "key.h" #include "joy.h" #include "timer.h" #include "dxxerror.h" #include "inferno.h" #include "game.h" #include "object.h" #include "player.h" #include "controls.h" #include "render.h" #include "args.h" #include "palette.h" #include "mouse.h" #include "kconfig.h" //look at keyboard, mouse, joystick, CyberMan, whatever, and set //physics vars rotvel, velocity void read_flying_controls( object * obj ) { Assert(FrameTime > 0); //Get MATT if hit this! // Couldn't the "50" in the next three lines be changed to "64" with no ill effect? obj->mtype.phys_info.rotthrust.x = Controls.pitch_time; obj->mtype.phys_info.rotthrust.y = Controls.heading_time; obj->mtype.phys_info.rotthrust.z = Controls.bank_time; // Set object's thrust vector for forward/backward vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->orient.fvec, Controls.forward_thrust_time ); // slide left/right vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.rvec, Controls.sideways_thrust_time ); // slide up/down vm_vec_scale_add2(&obj->mtype.phys_info.thrust,&obj->orient.uvec, Controls.vertical_thrust_time ); if (obj->mtype.phys_info.flags & PF_WIGGLE) { fix swiggle; fix_fastsincos(((fix)GameTime64), &swiggle, NULL); if (FrameTime < F1_0) // Only scale wiggle if getting at least 1 FPS, to avoid causing the opposite problem. swiggle = fixmul(swiggle*30, FrameTime); //make wiggle fps-independant (based on pre-scaled amount of wiggle at 30 FPS) vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&obj->orient.uvec,fixmul(swiggle,Player_ship->wiggle)); } // As of now, obj->mtype.phys_info.thrust & obj->mtype.phys_info.rotthrust are // in units of time... In other words, if thrust==FrameTime, that // means that the user was holding down the Max_thrust key for the // whole frame. So we just scale them up by the max, and divide by // FrameTime to make them independant of framerate // Prevent divide overflows on high frame rates. // In a signed divide, you get an overflow if num >= div<<15 { fix ft = FrameTime; // Note, you must check for ft < F1_0/2, else you can get an overflow on the << 15. if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_thrust)) { ft = (Player_ship->max_thrust >> 15) + 1; } vm_vec_scale( &obj->mtype.phys_info.thrust, fixdiv(Player_ship->max_thrust,ft) ); if ((ft < F1_0/2) && (ft << 15 <= Player_ship->max_rotthrust)) { ft = (Player_ship->max_thrust >> 15) + 1; } vm_vec_scale( &obj->mtype.phys_info.rotthrust, fixdiv(Player_ship->max_rotthrust,ft) ); } //moved here by WraithX if (Player_is_dead) { //vm_vec_zero(&obj->mtype.phys_info.rotthrust); //let dead players rotate, changed by WraithX vm_vec_zero(&obj->mtype.phys_info.thrust); //don't let dead players move, changed by WraithX return; }//end if } dxx-rebirth-0.58.1-d1x/main/controls.h000066400000000000000000000034311217717257200175130ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/controls.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:43:28 $ * * Header for controls.c * * $Log: controls.h,v $ * Revision 1.1.1.1 2006/03/17 19:43:28 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:14 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:27:17 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.4 1994/07/21 18:15:33 matt * Ripped out a bunch of unused stuff * * Revision 1.3 1994/07/15 09:32:08 john * Changes player movement. * * Revision 1.2 1994/06/30 19:02:22 matt * Moved flying controls code from physics.c to controls.c * * Revision 1.1 1994/06/30 18:41:36 matt * Initial revision * * */ #ifndef _CONTROLS_H #define _CONTROLS_H extern int Cyberman_installed; //SWIFT device present void read_flying_controls( object * obj ); extern ubyte Controls_stopped; extern ubyte Controls_always_move; #endif dxx-rebirth-0.58.1-d1x/main/credits.c000066400000000000000000000133771217717257200173120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to display the credits. * */ #include #include #include #include #include #include "dxxerror.h" #include "pstypes.h" #include "gr.h" #include "window.h" #include "key.h" #include "mouse.h" #include "palette.h" #include "game.h" #include "timer.h" #include "gamefont.h" #include "pcx.h" #include "u_mem.h" #include "screens.h" #include "digi.h" #include "rbaudio.h" #include "text.h" #include "songs.h" #include "menu.h" #include "config.h" #define ROW_SPACING (SHEIGHT / 17) #define NUM_LINES 20 //14 #define CREDITS_FILE "credits.tex" typedef struct credits { PHYSFS_file * file; int have_bin_file; char buffer[NUM_LINES][80]; int buffer_line; int first_line_offset; int extra_inc; int done; int row; grs_bitmap backdrop; } credits; int credits_handler(window *wind, d_event *event, credits *cr) { int j, l, y; char * tempp; switch (event->type) { case EVENT_KEY_COMMAND: if (!call_default_handler(event)) // if not print screen, debug etc window_close(wind); return 1; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: if (event_mouse_get_button(event) == MBTN_LEFT || event_mouse_get_button(event) == MBTN_RIGHT) { window_close(wind); return 1; } break; case EVENT_IDLE: if (cr->done>NUM_LINES) { window_close(wind); return 0; } break; case EVENT_WINDOW_DRAW: timer_delay(F1_0/17); if (cr->row == 0) { do { cr->buffer_line = (cr->buffer_line+1) % NUM_LINES; if (PHYSFSX_fgets( cr->buffer[cr->buffer_line], 80, cr->file )) { char *p; if (cr->have_bin_file) // is this a binary tbl file decode_text_line (cr->buffer[cr->buffer_line]); p = strchr(&cr->buffer[cr->buffer_line][0],'\n'); if (p) *p = '\0'; } else { //fseek( file, 0, SEEK_SET); cr->buffer[cr->buffer_line][0] = 0; cr->done++; } } while (cr->extra_inc--); cr->extra_inc = 0; } // cheap but effective: towards end of credits sequence, fade out the music volume if (cr->done >= NUM_LINES-16) { static int curvol = -10; if (curvol == -10) curvol = GameCfg.MusicVolume; if (curvol > (NUM_LINES-cr->done)/2) { curvol = (NUM_LINES-cr->done)/2; songs_set_volume(curvol); } } y = cr->first_line_offset - cr->row; show_fullscr(&cr->backdrop); for (j=0; jbuffer_line + j + 1 ) % NUM_LINES; s = cr->buffer[l]; if ( s[0] == '!' ) { s++; } else if ( s[0] == '$' ) { gr_set_curfont( HUGE_FONT ); s++; } else if ( s[0] == '*' ) { gr_set_curfont( MEDIUM3_FONT ); s++; } else gr_set_curfont( MEDIUM2_FONT ); tempp = strchr( s, '\t' ); if ( !tempp ) { // Wacky Fast Credits thing int w, h, aw; gr_get_string_size( s, &w, &h, &aw); gr_string( 0x8000, y, s ); } y += ROW_SPACING; } cr->row += SHEIGHT/200; if (cr->row >= ROW_SPACING) cr->row = 0; break; case EVENT_WINDOW_CLOSE: gr_free_bitmap_data (&cr->backdrop); PHYSFS_close(cr->file); songs_set_volume(GameCfg.MusicVolume); songs_play_song( SONG_TITLE, 1 ); d_free(cr); break; default: break; } return 0; } //if filename passed is NULL, show normal credits void credits_show(char *credits_filename) { credits *cr; window *wind; int i; int pcx_error; char * tempp; char filename[32]; ubyte backdrop_palette[768]; MALLOC(cr, credits, 1); if (!cr) return; cr->have_bin_file = 0; cr->buffer_line = 0; cr->first_line_offset = 0; cr->extra_inc = 0; cr->done = 0; cr->row = 0; // Clear out all tex buffer lines. for (i=0; ibuffer[i][0] = 0; sprintf(filename, "%s", CREDITS_FILE); cr->have_bin_file = 0; if (credits_filename) { strcpy(filename,credits_filename); cr->have_bin_file = 1; } cr->file = PHYSFSX_openReadBuffered( filename ); if (cr->file == NULL) { char nfile[32]; if (credits_filename) { d_free(cr); return; //ok to not find special filename } tempp = strchr(filename, '.'); *tempp = '\0'; sprintf(nfile, "%s.txb", filename); cr->file = PHYSFSX_openReadBuffered(nfile); if (cr->file == NULL) Error("Missing CREDITS.TEX and CREDITS.TXB file\n"); cr->have_bin_file = 1; } set_screen_mode(SCREEN_MENU); cr->backdrop.bm_data=NULL; pcx_error = pcx_read_bitmap(STARS_BACKGROUND,&cr->backdrop, BM_LINEAR,backdrop_palette); if (pcx_error != PCX_ERROR_NONE) { PHYSFS_close(cr->file); d_free(cr); return; } songs_play_song( SONG_CREDITS, 1 ); gr_remap_bitmap_good( &cr->backdrop,backdrop_palette, -1, -1 ); gr_set_current_canvas(NULL); show_fullscr(&cr->backdrop); gr_palette_load( gr_palette ); key_flush(); wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))credits_handler, cr); if (!wind) { d_event event = { EVENT_WINDOW_CLOSE }; credits_handler(NULL, &event, cr); return; } while (window_exists(wind)) event_process(); } dxx-rebirth-0.58.1-d1x/main/credits.h000066400000000000000000000015531217717257200173100ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes for the credit sequence. * */ #ifndef _CREDITS_H #define _CREDITS_H void credits_show(char *credits_filename); #endif dxx-rebirth-0.58.1-d1x/main/custom.c000066400000000000000000000347071217717257200171670ustar00rootroot00000000000000/* * Load custom textures & robot data */ #include #include "gr.h" #include "pstypes.h" #include "piggy.h" #include "textures.h" #include "polyobj.h" #include "weapon.h" #include "digi.h" #include "hash.h" #include "u_mem.h" #include "custom.h" //#define D2TMAP_CONV // used for testing extern hashtable AllBitmapsNames; extern hashtable AllDigiSndNames; struct snd_info { unsigned int length; ubyte *data; }; typedef struct DiskBitmapHeader2 { char name[8]; ubyte dflags; ubyte width; ubyte height; ubyte hi_wh; ubyte flags; ubyte avg_color; int offset; } __pack__ DiskBitmapHeader2; typedef struct DiskBitmapHeader { char name[8]; ubyte dflags; ubyte width; ubyte height; ubyte flags; ubyte avg_color; int offset; } __pack__ DiskBitmapHeader; typedef struct DiskSoundHeader { char name[8]; int length; int data_length; int offset; } __pack__ DiskSoundHeader; struct custom_info { int offset; int repl_idx; // 0x80000000 -> sound, -1 -> n/a unsigned int flags; int width, height; }; grs_bitmap BitmapOriginal[MAX_BITMAP_FILES]; struct snd_info SoundOriginal[MAX_SOUND_FILES]; static void change_ext(char *filename, const char *newext, int filename_size) { char *p; int len, extlen; len = strlen(filename); extlen = strlen(newext); if ((p = strrchr(filename, '.'))) { len = p - filename; *p = 0; } if (len + extlen + 1 < filename_size) { strcat(filename, "."); strcat(filename, newext); } } int load_pig1(PHYSFS_file *f, int num_bitmaps, int num_sounds, int *num_custom, struct custom_info **ci) { int data_ofs; int i; struct custom_info *cip; DiskBitmapHeader bmh; DiskSoundHeader sndh; char name[15]; *num_custom = 0; if ((unsigned int)num_bitmaps <= MAX_BITMAP_FILES) // 0 && num_bitmaps < PHYSFS_fileLength(f)) // >=v1.4 pig? { PHYSFSX_fseek(f, num_bitmaps, SEEK_SET); data_ofs = num_bitmaps + 8; num_bitmaps = PHYSFSX_readInt(f); num_sounds = PHYSFSX_readInt(f); } else return -1; // invalid pig file if ((unsigned int)num_bitmaps >= MAX_BITMAP_FILES || (unsigned int)num_sounds >= MAX_SOUND_FILES) return -1; // invalid pig file if (!(*ci = cip = d_malloc((num_bitmaps + num_sounds) * sizeof(struct custom_info)))) return -1; // out of memory data_ofs += num_bitmaps * sizeof(DiskBitmapHeader) + num_sounds * sizeof(DiskSoundHeader); i = num_bitmaps; while (i--) { if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader), 1) < 1) { d_free(*ci); return -1; } memcpy( name, bmh.name, 8 ); name[8] = 0; if (bmh.dflags & DBM_FLAG_ABM) sprintf(strchr(name, 0), "#%d", bmh.dflags & 63); cip->offset = bmh.offset + data_ofs; cip->repl_idx = hashtable_search(&AllBitmapsNames, name); cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE); cip->width = bmh.width + ((bmh.dflags & DBM_FLAG_LARGE) ? 256 : 0); cip->height = bmh.height; cip++; } i = num_sounds; while (i--) { if (PHYSFS_read(f, &sndh, sizeof(DiskSoundHeader), 1) < 1) { d_free(*ci); return -1; } memcpy(name, sndh.name, 8); name[8] = 0; cip->offset = sndh.offset + data_ofs; cip->repl_idx = hashtable_search(&AllDigiSndNames, name) | 0x80000000; cip->width = sndh.length; cip++; } *num_custom = num_bitmaps + num_sounds; return 0; } int load_pog(PHYSFS_file *f, int pog_sig, int pog_ver, int *num_custom, struct custom_info **ci) { int data_ofs; int num_bitmaps; int no_repl = 0; int i; struct custom_info *cip; DiskBitmapHeader2 bmh; #ifdef D2TMAP_CONV int x, j, N_d2tmap; int *d2tmap = NULL; PHYSFS_file *f2 = NULL; if ((f2 = PHYSFSX_openReadBuffered("d2tmap.bin"))) { N_d2tmap = PHYSFSX_readInt(f2); if ((d2tmap = d_malloc(N_d2tmap * sizeof(d2tmap[0])))) for (i = 0; i < N_d2tmap; i++) d2tmap[i] = PHYSFSX_readShort(f2); PHYSFS_close(f2); } #endif *num_custom = 0; if (pog_sig == 0x47495050 && pog_ver == 2) /* PPIG */ no_repl = 1; else if (pog_sig != 0x474f5044 || pog_ver != 1) /* DPOG */ return -1; // no pig2/pog file/unknown version num_bitmaps = PHYSFSX_readInt(f); if (!(*ci = cip = d_malloc(num_bitmaps * sizeof(struct custom_info)))) return -1; // out of memory data_ofs = 12 + num_bitmaps * sizeof(DiskBitmapHeader2); if (!no_repl) { i = num_bitmaps; while (i--) (cip++)->repl_idx = PHYSFSX_readShort(f); cip = *ci; data_ofs += num_bitmaps * 2; } #ifdef D2TMAP_CONV if (d2tmap) for (i = 0; i < num_bitmaps; i++) { x = cip[i].repl_idx; cip[i].repl_idx = -1; for (j = 0; j < N_d2tmap; j++) if (x == d2tmap[j]) { cip[i].repl_idx = Textures[j % NumTextures].index; break; } } #endif i = num_bitmaps; while (i--) { if (PHYSFS_read(f, &bmh, sizeof(DiskBitmapHeader2), 1) < 1) { d_free(*ci); return -1; } cip->offset = bmh.offset + data_ofs; cip->flags = bmh.flags & (BM_FLAG_TRANSPARENT | BM_FLAG_SUPER_TRANSPARENT | BM_FLAG_NO_LIGHTING | BM_FLAG_RLE); cip->width = bmh.width + ((bmh.hi_wh & 15) << 8); cip->height = bmh.height + ((bmh.hi_wh >> 4) << 8); cip++; } *num_custom = num_bitmaps; return 0; } // load custom textures/sounds from pog/pig file // returns 0 if ok, <0 on error int load_pigpog(char *pogname) { int num_custom; grs_bitmap *bmp; digi_sound *snd; ubyte *p; PHYSFS_file *f; struct custom_info *custom_info, *cip; int i, j, rc = -1; unsigned int x = 0; if (!(f = PHYSFSX_openReadBuffered((char *)pogname))) return -1; // pog file doesn't exist i = PHYSFSX_readInt(f); x = PHYSFSX_readInt(f); if (load_pog(f, i, x, &num_custom, &custom_info) && load_pig1(f, i, x, &num_custom, &custom_info)) { if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } cip = custom_info; i = num_custom; while (i--) { x = cip->repl_idx; if (cip->repl_idx >= 0) { PHYSFSX_fseek( f, cip->offset, SEEK_SET ); if ( cip->flags & BM_FLAG_RLE ) j = PHYSFSX_readInt(f); else j = cip->width * cip->height; if (!(p = d_malloc(j))) { if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } bmp = &GameBitmaps[x]; if (BitmapOriginal[x].bm_flags & 0x80) // already customized? gr_free_bitmap_data(bmp); else { // save original bitmap info BitmapOriginal[x] = *bmp; BitmapOriginal[x].bm_flags |= 0x80; if (GameBitmapOffset[x]) // from pig? { BitmapOriginal[x].bm_flags |= BM_FLAG_PAGED_OUT; BitmapOriginal[x].bm_data = (ubyte *)(size_t)GameBitmapOffset[x]; } } GameBitmapOffset[x] = 0; // not in pig memset(bmp, 0, sizeof(*bmp)); gr_init_bitmap (bmp, 0, 0, 0, cip->width, cip->height, cip->width, p); gr_set_bitmap_flags(bmp, cip->flags & 255); bmp->avg_color = cip->flags >> 8; if ( cip->flags & BM_FLAG_RLE ) { int *ip = (int *)p; *ip = j; p += 4; j -= 4; } if (PHYSFS_read(f, p, 1, j) < 1) { if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } } else if ((cip->repl_idx + 1) < 0) { PHYSFSX_fseek( f, cip->offset, SEEK_SET ); snd = &GameSounds[x & 0x7fffffff]; if (!(p = d_malloc(j = cip->width))) { if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } if (SoundOriginal[x & 0x7fffffff].length & 0x80000000) // already customized? d_free(snd->data); else { #ifdef ALLEGRO SoundOriginal[x & 0x7fffffff].length = snd->len | 0x80000000; #else SoundOriginal[x & 0x7fffffff].length = snd->length | 0x80000000; #endif SoundOriginal[x & 0x7fffffff].data = snd->data; } #ifdef ALLEGRO snd->loop_end = snd->len = j; #else snd->length = j; #endif snd->data = p; if (PHYSFS_read(f, p, j, 1) < 1) { if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } } cip++; } rc = 0; if (num_custom) d_free(custom_info); PHYSFS_close(f); return rc; } int read_d2_robot_info(PHYSFS_file *fp, robot_info *ri) { int j, k; ri->model_num = PHYSFSX_readInt(fp); for (j = 0; j < MAX_GUNS; j++) PHYSFSX_readVector(&ri->gun_points[j], fp); for (j = 0; j < MAX_GUNS; j++) ri->gun_submodels[j] = PHYSFSX_readByte(fp); ri->exp1_vclip_num = PHYSFSX_readShort(fp); ri->exp1_sound_num = PHYSFSX_readShort(fp); ri->exp2_vclip_num = PHYSFSX_readShort(fp); ri->exp2_sound_num = PHYSFSX_readShort(fp); ri->weapon_type = PHYSFSX_readByte(fp); if (ri->weapon_type >= N_weapon_types) ri->weapon_type = 0; /*ri->weapon_type2 =*/ PHYSFSX_readByte(fp); ri->n_guns = PHYSFSX_readByte(fp); ri->contains_id = PHYSFSX_readByte(fp); ri->contains_count = PHYSFSX_readByte(fp); ri->contains_prob = PHYSFSX_readByte(fp); ri->contains_type = PHYSFSX_readByte(fp); /*ri->kamikaze =*/ PHYSFSX_readByte(fp); ri->score_value = PHYSFSX_readShort(fp); /*ri->badass =*/ PHYSFSX_readByte(fp); /*ri->energy_drain =*/ PHYSFSX_readByte(fp); ri->lighting = PHYSFSX_readFix(fp); ri->strength = PHYSFSX_readFix(fp); ri->mass = PHYSFSX_readFix(fp); ri->drag = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->field_of_view[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->firing_wait[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) /*ri->firing_wait2[j] =*/ PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->turn_time[j] = PHYSFSX_readFix(fp); #if 0 // not used in d1, removed in d2 for (j = 0; j < NDL; j++) ri->fire_power[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->shield[j] = PHYSFSX_readFix(fp); #endif for (j = 0; j < NDL; j++) ri->max_speed[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->circle_distance[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri->rapidfire_count[j] = PHYSFSX_readByte(fp); for (j = 0; j < NDL; j++) ri->evade_speed[j] = PHYSFSX_readByte(fp); ri->cloak_type = PHYSFSX_readByte(fp); ri->attack_type = PHYSFSX_readByte(fp); ri->see_sound = PHYSFSX_readByte(fp); ri->attack_sound = PHYSFSX_readByte(fp); ri->claw_sound = PHYSFSX_readByte(fp); /*ri->taunt_sound =*/ PHYSFSX_readByte(fp); ri->boss_flag = PHYSFSX_readByte(fp); /*ri->companion =*/ PHYSFSX_readByte(fp); /*ri->smart_blobs =*/ PHYSFSX_readByte(fp); /*ri->energy_blobs =*/ PHYSFSX_readByte(fp); /*ri->thief =*/ PHYSFSX_readByte(fp); /*ri->pursuit =*/ PHYSFSX_readByte(fp); /*ri->lightcast =*/ PHYSFSX_readByte(fp); /*ri->death_roll =*/ PHYSFSX_readByte(fp); /*ri->flags =*/ PHYSFSX_readByte(fp); /*ri->pad[0] =*/ PHYSFSX_readByte(fp); /*ri->pad[1] =*/ PHYSFSX_readByte(fp); /*ri->pad[2] =*/ PHYSFSX_readByte(fp); /*ri->deathroll_sound =*/ PHYSFSX_readByte(fp); /*ri->glow =*/ PHYSFSX_readByte(fp); /*ri->behavior =*/ PHYSFSX_readByte(fp); /*ri->aim =*/ PHYSFSX_readByte(fp); for (j = 0; j < MAX_GUNS + 1; j++) { for (k = 0; k < N_ANIM_STATES; k++) { ri->anim_states[j][k].n_joints = PHYSFSX_readShort(fp); ri->anim_states[j][k].offset = PHYSFSX_readShort(fp); } } ri->always_0xabcd = PHYSFSX_readInt(fp); return 1; } void load_hxm(char *hxmname) { unsigned int repl_num; int i; PHYSFS_file *f; int n_items; if (!(f = PHYSFSX_openReadBuffered((char *)hxmname))) return; // hxm file doesn't exist if (PHYSFSX_readInt(f) != 0x21584d48) /* HMX! */ { PHYSFS_close(f); // invalid hxm file return; } if (PHYSFSX_readInt(f) != 1) { PHYSFS_close(f); // unknown version return; } // read robot info if ((n_items = PHYSFSX_readInt(f)) != 0) { for (i = 0; i < n_items; i++) { repl_num = PHYSFSX_readInt(f); if (repl_num >= MAX_ROBOT_TYPES) { PHYSFSX_fseek(f, 480, SEEK_CUR); /* sizeof d2_robot_info */ } else { if (!(read_d2_robot_info(f, &Robot_info[repl_num]))) { PHYSFS_close(f); return; } } } } // read joint positions if ((n_items = PHYSFSX_readInt(f)) != 0) { for (i = 0; i < n_items; i++) { repl_num = PHYSFSX_readInt(f); if (repl_num >= MAX_ROBOT_JOINTS) PHYSFSX_fseek(f, sizeof(jointpos), SEEK_CUR); else { if (PHYSFS_read(f, &Robot_joints[repl_num], sizeof(jointpos), 1) < 1) { PHYSFS_close(f); return; } } } } // read polygon models if ((n_items = PHYSFSX_readInt(f)) != 0) { for (i = 0; i < n_items; i++) { polymodel *pm; repl_num = PHYSFSX_readInt(f); if (repl_num >= MAX_POLYGON_MODELS) { PHYSFSX_readInt(f); // skip n_models PHYSFSX_fseek(f, 734 - 8 + PHYSFSX_readInt(f) + 8, SEEK_CUR); } else { pm = &Polygon_models[repl_num]; if (pm->model_data) d_free(pm->model_data); if (PHYSFS_read(f, pm, sizeof(polymodel), 1) < 1) { pm->model_data = NULL; PHYSFS_close(f); return; } if (!(pm->model_data = d_malloc(pm->model_data_size))) { PHYSFS_close(f); return; } if (PHYSFS_read(f, pm->model_data, pm->model_data_size, 1) < 1) { pm->model_data = NULL; PHYSFS_close(f); return; } Dying_modelnums[repl_num] = PHYSFSX_readInt(f); Dead_modelnums[repl_num] = PHYSFSX_readInt(f); } } } // read object bitmaps if ((n_items = PHYSFSX_readInt(f)) != 0) { for (i = 0; i < n_items; i++) { repl_num = PHYSFSX_readInt(f); if (repl_num >= MAX_OBJ_BITMAPS) PHYSFSX_fseek(f, 2, SEEK_CUR); else ObjBitmaps[repl_num].index = PHYSFSX_readShort(f); } } PHYSFS_close(f); } // undo customized items void custom_remove() { int i; grs_bitmap *bmo = BitmapOriginal; grs_bitmap *bmp = GameBitmaps; for (i = 0; i < MAX_BITMAP_FILES; bmo++, bmp++, i++) if (bmo->bm_flags & 0x80) { gr_free_bitmap_data(bmp); *bmp = *bmo; if (bmo->bm_flags & BM_FLAG_PAGED_OUT) { GameBitmapOffset[i] = (int)(size_t)BitmapOriginal[i].bm_data; gr_set_bitmap_flags(bmp, BM_FLAG_PAGED_OUT); gr_set_bitmap_data(bmp, Piggy_bitmap_cache_data); } else { gr_set_bitmap_flags(bmp, bmo->bm_flags & 0x7f); } bmo->bm_flags = 0; } for (i = 0; i < MAX_SOUND_FILES; i++) if (SoundOriginal[i].length & 0x80000000) { d_free(GameSounds[i].data); GameSounds[i].data = SoundOriginal[i].data; #ifdef ALLEGRO GameSounds[i].len = SoundOriginal[i].length & 0x7fffffff; #else GameSounds[i].length = SoundOriginal[i].length & 0x7fffffff; #endif SoundOriginal[i].length = 0; } } void load_custom_data(char *level_name) { char custom_file[64]; custom_remove(); strncpy(custom_file, level_name, 63); custom_file[63] = 0; change_ext(custom_file, "pg1", sizeof(custom_file)); load_pigpog(custom_file); change_ext(custom_file, "dtx", sizeof(custom_file)); load_pigpog(custom_file); change_ext(custom_file, "hx1", sizeof(custom_file)); load_hxm(custom_file); } void custom_close() { custom_remove(); } dxx-rebirth-0.58.1-d1x/main/custom.h000066400000000000000000000005611217717257200171630ustar00rootroot00000000000000#ifndef _CUSTOM_H #define _CUSTOM_H /* from piggy.c */ #define DBM_FLAG_LARGE 128 // Flags added onto the flags struct in b #define DBM_FLAG_ABM 64 extern int GameBitmapOffset[MAX_BITMAP_FILES]; extern ubyte GameBitmapFlags[MAX_BITMAP_FILES]; extern ubyte * Piggy_bitmap_cache_data; void load_custom_data(char *level_file); void custom_close(); #endif dxx-rebirth-0.58.1-d1x/main/digi.h000066400000000000000000000101171217717257200165630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Include file for sound hardware. * */ #ifndef _DIGI_H #define _DIGI_H #include "pstypes.h" #include "vecmat.h" typedef struct digi_sound { int bits; int freq; int length; ubyte * data; } digi_sound; extern int digi_get_settings(); extern int digi_init(); extern void digi_reset(); extern void digi_close(); // Volume is max at F1_0. extern void digi_play_sample( int sndnum, fix max_volume ); extern void digi_play_sample_once( int sndnum, fix max_volume ); extern int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume ); extern int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume ); // Same as above, but you pass the max distance sound can be heard. The old way uses f1_0*256 for max_distance. extern int digi_link_sound_to_object2( int soundnum, short objnum, int forever, fix max_volume, fix max_distance ); extern int digi_link_sound_to_pos2( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance ); extern void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups ); // Volume from 0-0x7fff extern void digi_init_sounds(); extern void digi_sync_sounds(); extern void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum ); extern void digi_kill_sound_linked_to_object( int objnum ); extern void digi_set_digi_volume( int dvolume ); extern void digi_set_volume( int dvolume ); extern int digi_is_sound_playing(int soundno); extern void digi_pause_digi_sounds(); extern void digi_resume_digi_sounds(); extern void digi_set_max_channels(int n); extern int digi_get_max_channels(); extern int digi_xlat_sound(int soundno); extern void digi_stop_sound( int channel ); // Volume 0-F1_0 extern int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, int soundobj); // Stops all sounds that are playing void digi_stop_all_channels(); void digi_stop_digi_sounds(); extern void digi_end_sound( int channel ); extern void digi_set_channel_pan( int channel, int pan ); extern void digi_set_channel_volume( int channel, int volume ); extern int digi_is_channel_playing(int channel); extern void digi_debug(); extern void digi_play_sample_looping( int soundno, fix max_volume,int loop_start, int loop_end ); extern void digi_change_looping_volume( fix volume ); extern void digi_stop_looping_sound(); // Plays a queued voice sound. extern void digi_start_sound_queued( short soundnum, fix volume ); // Following declarations are for the runtime switching system #define SAMPLE_RATE_11K 11025 #define SAMPLE_RATE_22K 22050 #define SAMPLE_RATE_44K 44100 #define SDLMIXER_SYSTEM 1 #define SDLAUDIO_SYSTEM 2 #define MUSIC_TYPE_NONE 0 #define MUSIC_TYPE_BUILTIN 1 #define MUSIC_TYPE_REDBOOK 2 #define MUSIC_TYPE_CUSTOM 3 // play-order definitions for custom music #define MUSIC_CM_PLAYORDER_CONT 0 #define MUSIC_CM_PLAYORDER_LEVEL 1 #define MUSIC_CM_PLAYORDER_RAND 2 #define SOUND_MAX_VOLUME F1_0 / 2 extern int digi_volume; extern int digi_sample_rate; void digi_select_system(int); #ifdef _WIN32 // Windows native-MIDI stuff. void digi_win32_set_midi_volume( int mvolume ); int digi_win32_play_midi_song( char * filename, int loop ); void digi_win32_pause_midi_song(); void digi_win32_resume_midi_song(); void digi_win32_stop_midi_song(); #endif #endif dxx-rebirth-0.58.1-d1x/main/digicomp.c000066400000000000000000000056621217717257200174460ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/digicomp.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:42:50 $ * * Routines for manipulating digi samples. * * $Log: digicomp.c,v $ * Revision 1.1.1.1 2006/03/17 19:42:50 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:06:00 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:33:04 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.2 1994/12/07 18:42:21 john * Initial, unused version.. * * Revision 1.1 1994/12/05 09:37:13 john * Initial revision * * */ #include "soscomp.h" #pragma pack (4); // Use 32-bit packing! #pragma off (check_stack); // No stack checking! #include "sos.h" #include "sosm.h" ubyte digicomp_initialized = 0; #define MAX_DIGI_BLOCKS 32 ubyte * digicomp_memory[ MAX_DIGI_MEMORY ]; int N_blocks = 0; int Next_block = 0; typedef struct digi_block { int offset; int len; int soundno; } digi_block; digi_block Digi_blocks[MAX_DIGI_BLOCKS]; void digicomp_init() { int i; if ( digicomp_initialized ) return; digicomp_initialized = 1; Digi_blocks[0].len = MAX_DIGI_MEMORY; Digi_blocks[0].offset = 0; Digi_blocks[0].soundno = -1; N_blocks = 1; for (i=1; i-1) && ( Digi_blocks[i].len < mysize ) ) { i++; if ( i > MAX_DIGI_BLOCKS ) i = 0; if ( i == Next_block ) { // An unused block that this can fit into wasn't found, so find the next one it can fit into // and stop it... return NULL; } } } dxx-rebirth-0.58.1-d1x/main/digicomp.h000066400000000000000000000026671217717257200174550ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/digicomp.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:42:51 $ * * prototypes for digicomp.c * * $Log: digicomp.h,v $ * Revision 1.1.1.1 2006/03/17 19:42:51 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:14 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:27:54 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.2 1994/12/07 18:42:30 john * Initial, unused version.. * * Revision 1.1 1994/12/05 09:37:23 john * Initial revision * * */ #ifndef _DIGICOMP_H #define _DIGICOMP_H #endif dxx-rebirth-0.58.1-d1x/main/digiobj.c000066400000000000000000000552271217717257200172640ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include #include #include #include "fix.h" #include "object.h" #include "timer.h" #include "joy.h" #include "digi.h" #include "sounds.h" #include "args.h" #include "key.h" #include "newdemo.h" #include "game.h" #include "dxxerror.h" #include "wall.h" #include "piggy.h" #include "text.h" #include "kconfig.h" #include "config.h" #define SOF_USED 1 // Set if this sample is used #define SOF_PLAYING 2 // Set if this sample is playing on a channel #define SOF_LINK_TO_OBJ 4 // Sound is linked to a moving object. If object dies, then finishes play and quits. #define SOF_LINK_TO_POS 8 // Sound is linked to segment, pos #define SOF_PLAY_FOREVER 16 // Play forever (or until level is stopped), otherwise plays once #define SOF_PERMANENT 32 // Part of the level, like a waterfall or fan typedef struct sound_object { short signature; // A unique signature to this sound ubyte flags; // Used to tell if this slot is used and/or currently playing, and how long. ubyte pad; // Keep alignment fix max_volume; // Max volume that this sound is playing at fix max_distance; // The max distance that this sound can be heard at... int volume; // Volume that this sound is playing at int pan; // Pan value that this sound is playing at int channel; // What channel this is playing on, -1 if not playing short soundnum; // The sound number that is playing int loop_start; // The start point of the loop. -1 means no loop int loop_end; // The end point of the loop union { struct { short segnum; // Used if SOF_LINK_TO_POS field is used short sidenum; vms_vector position; } pos; struct { short objnum; // Used if SOF_LINK_TO_OBJ field is used short objsignature; } obj; } link_type; } sound_object; #define MAX_SOUND_OBJECTS 150 sound_object SoundObjects[MAX_SOUND_OBJECTS]; short next_signature=0; int N_active_sound_objects=0; int digi_sounds_initialized=0; /* Find the sound which actually equates to a sound number */ int digi_xlat_sound(int soundno) { if (soundno < 0) return -1; if (GameArg.SysLowMem) { soundno = AltSounds[soundno]; if (soundno == 255) return -1; } //Assert(Sounds[soundno] != 255); //if hit this, probably using undefined sound if (Sounds[soundno] == 255) return -1; return Sounds[soundno]; } int digi_unxlat_sound(int soundno) { int i; ubyte *table = (GameArg.SysLowMem?AltSounds:Sounds); if ( soundno < 0 ) return -1; for (i=0;i -1 ) { *volume = max_volume - fixdiv(path_distance,max_distance); if (*volume > 0 ) { angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec); fix_sincos(angle_from_ear,&sinang,&cosang); if (GameCfg.ReverseStereo) cosang *= -1; *pan = (cosang + F1_0)/2; } else { *volume = 0; } } } } void digi_play_sample_once( int soundno, fix max_volume ) { if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_sound( soundno ); soundno = digi_xlat_sound(soundno); if (soundno < 0 ) return; // start the sample playing digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 ); } void digi_play_sample( int soundno, fix max_volume ) { if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_sound( soundno ); soundno = digi_xlat_sound(soundno); if (soundno < 0 ) return; // start the sample playing digi_start_sound( soundno, max_volume, 0xffff/2, 0, -1, -1, -1 ); } void digi_play_sample_3d( int soundno, int angle, int volume, int no_dups ) { no_dups = 1; if ( Newdemo_state == ND_STATE_RECORDING ) { if ( no_dups ) newdemo_record_sound_3d_once( soundno, angle, volume ); else newdemo_record_sound_3d( soundno, angle, volume ); } soundno = digi_xlat_sound(soundno); if (soundno < 0 ) return; if (volume < 10 ) return; // start the sample playing digi_start_sound( soundno, volume, angle, 0, -1, -1, -1 ); } void SoundQ_init(); void SoundQ_process(); void SoundQ_pause(); void digi_init_sounds() { int i; SoundQ_init(); digi_stop_all_channels(); digi_stop_looping_sound(); for (i=0; i -1 ) digi_looping_channel = digi_start_sound( digi_looping_sound, digi_looping_volume, 0xFFFF/2, 1, digi_looping_start, digi_looping_end, -1 ); } void digi_play_sample_looping( int soundno, fix max_volume,int loop_start, int loop_end ) { soundno = digi_xlat_sound(soundno); if (soundno < 0 ) return; if (digi_looping_channel>-1) digi_stop_sound( digi_looping_channel ); digi_looping_sound = soundno; digi_looping_volume = max_volume; digi_looping_start = loop_start; digi_looping_end = loop_end; digi_play_sample_looping_sub(); } void digi_change_looping_volume( fix volume ) { if ( digi_looping_channel > -1 ) digi_set_channel_volume( digi_looping_channel, volume ); digi_looping_volume = volume; } void digi_stop_looping_sound() { if ( digi_looping_channel > -1 ) digi_stop_sound( digi_looping_channel ); digi_looping_channel = -1; digi_looping_sound = -1; } void digi_pause_looping_sound() { if ( digi_looping_channel > -1 ) digi_stop_sound( digi_looping_channel ); digi_looping_channel = -1; } void digi_unpause_looping_sound() { digi_play_sample_looping_sub(); } //hack to not start object when loading level int Dont_start_sound_objects = 0; void digi_start_sound_object(int i) { // start sample structures SoundObjects[i].channel = -1; if ( SoundObjects[i].volume <= 0 ) return; if ( Dont_start_sound_objects ) return; // -- MK, 2/22/96 -- if ( Newdemo_state == ND_STATE_RECORDING ) // -- MK, 2/22/96 -- newdemo_record_sound_3d_once( digi_unxlat_sound(SoundObjects[i].soundnum), SoundObjects[i].pan, SoundObjects[i].volume ); // only use up to half the sound channels for "permanent" sounts if ((SoundObjects[i].flags & SOF_PERMANENT) && (N_active_sound_objects >= max(1, digi_max_channels / 4))) return; // start the sample playing SoundObjects[i].channel = digi_start_sound( SoundObjects[i].soundnum, SoundObjects[i].volume, SoundObjects[i].pan, SoundObjects[i].flags & SOF_PLAY_FOREVER, SoundObjects[i].loop_start, SoundObjects[i].loop_end, i ); if (SoundObjects[i].channel > -1 ) N_active_sound_objects++; } //sounds longer than this get their 3d aspects updated #define SOUND_3D_THRESHHOLD (digi_sample_rate * 3 / 2) //1.5 seconds int digi_link_sound_to_object3( int org_soundnum, short objnum, int forever, fix max_volume, fix max_distance, int loop_start, int loop_end ) { int i,volume,pan; object * objp; int soundnum; soundnum = digi_xlat_sound(org_soundnum); if ( max_volume < 0 ) return -1; // if ( max_volume > F1_0 ) max_volume = F1_0; if (soundnum < 0 ) return -1; if (GameSounds[soundnum].data==NULL) { Int3(); return -1; } if ((objnum<0)||(objnum>Highest_object_index)) return -1; if ( !forever ) { // && GameSounds[soundnum - SOUND_OFFSET].length < SOUND_3D_THRESHHOLD) { // Hack to keep sounds from building up... digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &Objects[objnum].pos, Objects[objnum].segnum, max_volume,&volume, &pan, max_distance ); digi_play_sample_3d( org_soundnum, pan, volume, 0 ); return -1; } if ( Newdemo_state == ND_STATE_RECORDING ) { newdemo_record_link_sound_to_object3( org_soundnum, objnum, max_volume, max_distance, loop_start, loop_end ); } for (i=0; iorient, &Viewer->pos, Viewer->segnum, &objp->pos, objp->segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); digi_start_sound_object(i); // If it's a one-shot sound effect, and it can't start right away, then // just cancel it and be done with it. if ( (SoundObjects[i].channel < 0) && (!(SoundObjects[i].flags & SOF_PLAY_FOREVER)) ) { SoundObjects[i].flags = 0; return -1; } } return SoundObjects[i].signature; } int digi_link_sound_to_object2( int org_soundnum, short objnum, int forever, fix max_volume, fix max_distance ) { return digi_link_sound_to_object3( org_soundnum, objnum, forever, max_volume, max_distance, -1, -1 ); } int digi_link_sound_to_object( int soundnum, short objnum, int forever, fix max_volume ) { return digi_link_sound_to_object2( soundnum, objnum, forever, max_volume, 256*F1_0 ); } int digi_link_sound_to_pos2( int org_soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume, fix max_distance ) { int i, volume, pan; int soundnum; soundnum = digi_xlat_sound(org_soundnum); if ( max_volume < 0 ) return -1; // if ( max_volume > F1_0 ) max_volume = F1_0; if (soundnum < 0 ) return -1; if (GameSounds[soundnum].data==NULL) { Int3(); return -1; } if ((segnum<0)||(segnum>Highest_segment_index)) return -1; if ( !forever ) { //&& GameSounds[soundnum - SOUND_OFFSET].length < SOUND_3D_THRESHHOLD) { // Hack to keep sounds from building up... digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, pos, segnum, max_volume, &volume, &pan, max_distance ); digi_play_sample_3d( org_soundnum, pan, volume, 0 ); return -1; } for (i=0; iorient, &Viewer->pos, Viewer->segnum, &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); digi_start_sound_object(i); // If it's a one-shot sound effect, and it can't start right away, then // just cancel it and be done with it. if ( (SoundObjects[i].channel < 0) && (!(SoundObjects[i].flags & SOF_PLAY_FOREVER)) ) { SoundObjects[i].flags = 0; return -1; } } return SoundObjects[i].signature; } int digi_link_sound_to_pos( int soundnum, short segnum, short sidenum, vms_vector * pos, int forever, fix max_volume ) { return digi_link_sound_to_pos2( soundnum, segnum, sidenum, pos, forever, max_volume, F1_0 * 256 ); } //if soundnum==-1, kill any sound void digi_kill_sound_linked_to_segment( int segnum, int sidenum, int soundnum ) { int i,killed; if (soundnum != -1) soundnum = digi_xlat_sound(soundnum); killed = 0; for (i=0; i -1 ) { digi_stop_sound( SoundObjects[i].channel ); N_active_sound_objects--; } SoundObjects[i].channel = -1; SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound killed++; } } } } void digi_kill_sound_linked_to_object( int objnum ) { int i,killed; killed = 0; if ( Newdemo_state == ND_STATE_RECORDING ) { newdemo_record_kill_sound_linked_to_object( objnum ); } for (i=0; i -1 ) { digi_stop_sound( SoundObjects[i].channel ); N_active_sound_objects--; } SoundObjects[i].channel = -1; SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound killed++; } } } } // John's new function, 2/22/96. void digi_record_sound_objects() { int i; for (i=0; i -1 ) { if ( !digi_is_channel_playing(SoundObjects[i].channel) ) { digi_end_sound( SoundObjects[i].channel ); SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound N_active_sound_objects--; continue; // Go on to next sound... } } } if ( SoundObjects[i].flags & SOF_LINK_TO_POS ) { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ ) { object * objp; if ( Newdemo_state == ND_STATE_PLAYBACK ) { int objnum; objnum = newdemo_find_object( SoundObjects[i].link_type.obj.objsignature ); if ( objnum > -1 ) { objp = &Objects[objnum]; } else { objp = &Objects[0]; } } else { objp = &Objects[SoundObjects[i].link_type.obj.objnum]; } if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].link_type.obj.objsignature)) { // The object that this is linked to is dead, so just end this sound if it is looping. if ( SoundObjects[i].channel>-1 ) { if (SoundObjects[i].flags & SOF_PLAY_FOREVER) digi_stop_sound( SoundObjects[i].channel ); else digi_end_sound( SoundObjects[i].channel ); N_active_sound_objects--; } SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; // Go on to next sound... } else { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &objp->pos, objp->segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } } if (oldvolume != SoundObjects[i].volume) { if ( SoundObjects[i].volume < 1 ) { // Sound is too far away, so stop it from playing. if ( SoundObjects[i].channel>-1 ) { if (SoundObjects[i].flags & SOF_PLAY_FOREVER) digi_stop_sound( SoundObjects[i].channel ); else digi_end_sound( SoundObjects[i].channel ); N_active_sound_objects--; SoundObjects[i].channel = -1; } if (! (SoundObjects[i].flags & SOF_PLAY_FOREVER)) { SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; } } else { if (SoundObjects[i].channel<0) { digi_start_sound_object(i); } else { digi_set_channel_volume( SoundObjects[i].channel, SoundObjects[i].volume ); } } } if (oldpan != SoundObjects[i].pan) { if (SoundObjects[i].channel>-1) digi_set_channel_pan( SoundObjects[i].channel, SoundObjects[i].pan ); } } } #ifndef NDEBUG // digi_sound_debug(); #endif } void digi_pause_digi_sounds() { int i; digi_pause_looping_sound(); for (i=0; i-1) ) { digi_stop_sound( SoundObjects[i].channel ); if (! (SoundObjects[i].flags & SOF_PLAY_FOREVER)) SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound N_active_sound_objects--; SoundObjects[i].channel = -1; } } digi_stop_all_channels(); SoundQ_pause(); } void digi_resume_digi_sounds() { digi_sync_sounds(); //don't think we really need to do this, but can't hurt digi_unpause_looping_sound(); } // Called by the code in digi.c when another sound takes this sound object's // slot because the sound was done playing. void digi_end_soundobj(int i) { Assert( SoundObjects[i].flags & SOF_USED ); Assert( SoundObjects[i].channel > -1 ); N_active_sound_objects--; SoundObjects[i].channel = -1; } void digi_stop_digi_sounds() { int i; digi_stop_looping_sound(); for (i=0; i -1 ) { digi_stop_sound( SoundObjects[i].channel ); N_active_sound_objects--; } SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound } } digi_stop_all_channels(); SoundQ_init(); } #ifndef NDEBUG int verify_sound_channel_free( int channel ) { int i; for (i=0; i -1 ) n_active_sound_objs++; } } digi_debug(); } #endif typedef struct sound_q { fix64 time_added; int soundnum; } sound_q; #define MAX_Q 32 #define MAX_LIFE F1_0*30 // After being queued for 30 seconds, don't play it sound_q SoundQ[MAX_Q]; int SoundQ_head, SoundQ_tail, SoundQ_num; int SoundQ_channel; void SoundQ_init() { SoundQ_head = SoundQ_tail = 0; SoundQ_num = 0; SoundQ_channel = -1; } void SoundQ_pause() { SoundQ_channel = -1; } void SoundQ_end() { // Current playing sound is stopped, so take it off the Queue SoundQ_head = (SoundQ_head+1); if ( SoundQ_head >= MAX_Q ) SoundQ_head = 0; SoundQ_num--; SoundQ_channel = -1; } void SoundQ_process() { if ( SoundQ_channel > -1 ) { if ( digi_is_channel_playing(SoundQ_channel) ) return; SoundQ_end(); } while ( SoundQ_head != SoundQ_tail ) { sound_q * q = &SoundQ[SoundQ_head]; if ( q->time_added+MAX_LIFE > timer_query() ) { SoundQ_channel = digi_start_sound(q->soundnum, F1_0+1, 0xFFFF/2, 0, -1, -1, -1 ); return; } else { // expired; remove from Queue SoundQ_end(); } } } void digi_start_sound_queued( short soundnum, fix volume ) { int i; soundnum = digi_xlat_sound(soundnum); if (soundnum < 0 ) return; i = SoundQ_tail+1; if ( i>=MAX_Q ) i = 0; // Make sure its loud so it doesn't get cancelled! if ( volume < F1_0+1 ) volume = F1_0 + 1; if ( i != SoundQ_head ) { SoundQ[SoundQ_tail].time_added = timer_query(); SoundQ[SoundQ_tail].soundnum = soundnum; SoundQ_num++; SoundQ_tail = i; } // Try to start it! SoundQ_process(); } dxx-rebirth-0.58.1-d1x/main/dumpmine.c000066400000000000000000000720721217717257200174700ustar00rootroot00000000000000/* * * Functions to dump text description of mine. * An editor-only function, called at mine load time. * To be read by a human to verify the correctness and completeness of a mine. * */ #include #include #include #include "console.h" #include "key.h" #include "gr.h" #include "palette.h" #include "inferno.h" #ifdef EDITOR #include "editor/editor.h" #endif #include "dxxerror.h" #include "object.h" #include "wall.h" #include "gamemine.h" #include "robot.h" #include "player.h" #include "newmenu.h" #include "textures.h" #include "bm.h" #include "menu.h" #include "switch.h" #include "fuelcen.h" #include "powerup.h" #include "hostage.h" #include "gameseq.h" #include "polyobj.h" #include "gamesave.h" #ifdef EDITOR void dump_used_textures_level(PHYSFS_file *my_file, int level_num); static void say_totals(PHYSFS_file *my_file, const char *level_name); extern ubyte bogus_data[64*64]; extern grs_bitmap bogus_bitmap; // -------------------------------------------------------------------------------- char *object_types(int objnum) { int type = Objects[objnum].type; Assert((type == OBJ_NONE) || ((type >= 0) && (type < MAX_OBJECT_TYPES))); return Object_type_names[type]; } // -------------------------------------------------------------------------------- char *object_ids(int objnum) { int type = Objects[objnum].type; int id = Objects[objnum].id; switch (type) { case OBJ_ROBOT: return Robot_names[id]; break; case OBJ_POWERUP: return Powerup_names[id]; break; } return NULL; } void err_printf(PHYSFS_file *my_file, char * format, ... ) { va_list args; char message[256]; va_start(args, format ); vsprintf(message,format,args); va_end(args); con_printf(CON_CRITICAL, "%s", message); PHYSFSX_printf(my_file, "%s", message); Errors_in_mine++; } void warning_printf(PHYSFS_file *my_file, char * format, ... ) { va_list args; char message[256]; va_start(args, format ); vsprintf(message,format,args); va_end(args); con_printf(CON_URGENT, "%s", message); PHYSFSX_printf(my_file, "%s", message); } // ----------------------------------------------------------------------------------------------------------- void write_exit_text(PHYSFS_file *my_file) { int i, j, count; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Exit stuff\n"); // ---------- Find exit triggers ---------- count=0; for (i=0; i 1) err_printf(my_file, "Error: Trigger %i is bound to %i walls.\n", i, count2); } if (count == 0) err_printf(my_file, "Error: No exit trigger in this mine.\n"); else if (count != 1) err_printf(my_file, "Error: More than one exit trigger in this mine.\n"); else PHYSFSX_printf(my_file, "\n"); // ---------- Find exit doors ---------- count = 0; for (i=0; i<=Highest_segment_index; i++) for (j=0; j 1) warning_printf(my_file, "Warning: %i doors are keyed to the blue key.\n", blue_count); if (red_count > 1) warning_printf(my_file, "Warning: %i doors are keyed to the red key.\n", red_count); if (gold_count > 1) warning_printf(my_file, "Warning: %i doors are keyed to the gold key.\n", gold_count); red_count2 = 0; blue_count2 = 0; gold_count2 = 0; for (i=0; i<=Highest_object_index; i++) { if (Objects[i].type == OBJ_POWERUP) if (Objects[i].id == POW_KEY_BLUE) { PHYSFSX_printf(my_file, "The BLUE key is object %i in segment %i\n", i, Objects[i].segnum); blue_count2++; } if (Objects[i].type == OBJ_POWERUP) if (Objects[i].id == POW_KEY_RED) { PHYSFSX_printf(my_file, "The RED key is object %i in segment %i\n", i, Objects[i].segnum); red_count2++; } if (Objects[i].type == OBJ_POWERUP) if (Objects[i].id == POW_KEY_GOLD) { PHYSFSX_printf(my_file, "The GOLD key is object %i in segment %i\n", i, Objects[i].segnum); gold_count2++; } if (Objects[i].contains_count) { if (Objects[i].contains_type == OBJ_POWERUP) { switch (Objects[i].contains_id) { case POW_KEY_BLUE: PHYSFSX_printf(my_file, "The BLUE key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum); blue_count2 += Objects[i].contains_count; break; case POW_KEY_GOLD: PHYSFSX_printf(my_file, "The GOLD key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum); gold_count2 += Objects[i].contains_count; break; case POW_KEY_RED: PHYSFSX_printf(my_file, "The RED key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum); red_count2 += Objects[i].contains_count; break; default: break; } } } } if (blue_count) if (blue_count2 == 0) err_printf(my_file, "Error: There is a door keyed to the blue key, but no blue key!\n"); if (red_count) if (red_count2 == 0) err_printf(my_file, "Error: There is a door keyed to the red key, but no red key!\n"); if (gold_count) if (gold_count2 == 0) err_printf(my_file, "Error: There is a door keyed to the gold key, but no gold key!\n"); if (blue_count2 > 1) err_printf(my_file, "Error: There are %i blue keys!\n", blue_count2); if (red_count2 > 1) err_printf(my_file, "Error: There are %i red keys!\n", red_count2); if (gold_count2 > 1) err_printf(my_file, "Error: There are %i gold keys!\n", gold_count2); } // ------------------------------------------------------------------------------------------ void write_control_center_text(PHYSFS_file *my_file) { int i, count, objnum, count2; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Control Center stuff:\n"); count = 0; for (i=0; i<=Highest_segment_index; i++) if (Segments[i].special == SEGMENT_IS_CONTROLCEN) { count++; PHYSFSX_printf(my_file, "Segment %3i is a control center.\n", i); objnum = Segments[i].objects; count2 = 0; while (objnum != -1) { if (Objects[objnum].type == OBJ_CNTRLCEN) count2++; objnum = Objects[objnum].next; } if (count2 == 0) PHYSFSX_printf(my_file, "No control center object in control center segment.\n"); else if (count2 != 1) PHYSFSX_printf(my_file, "%i control center objects in control center segment.\n", count2); } if (count == 0) err_printf(my_file, "Error: No control center in this mine.\n"); else if (count != 1) err_printf(my_file, "Error: More than one control center in this mine.\n"); } // ------------------------------------------------------------------------------------------ void write_fuelcen_text(PHYSFS_file *my_file) { int i; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Fuel Center stuff: (Note: This means fuel, repair, materialize, control centers!)\n"); for (i=0; i 30) { PHYSFSX_printf(my_file, "\nAborted after %i links\n", depth); break; } } } PHYSFSX_printf(my_file, "\n"); } } // ------------------------------------------------------------------------------------------ // This routine is bogus. It assumes that all centers are matcens, which is not true. The setting of segnum is bogus. void write_matcen_text(PHYSFS_file *my_file) { int i, j, k; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Materialization centers:\n"); for (i=0; i> 16), Walls[i].trigger, Walls[i].clip_num, Walls[i].keys, Walls[i].state); segnum = Walls[i].segnum; sidenum = Walls[i].sidenum; if (Segments[segnum].sides[sidenum].wall_num != i) err_printf(my_file, "Error: Wall %i points at segment %i, side %i, but that segment doesn't point back (it's wall_num = %i)\n", i, segnum, sidenum, Segments[segnum].sides[sidenum].wall_num); } for (i=0; isides[j]; if (sidep->wall_num != -1) { if (wall_flags[sidep->wall_num]) err_printf(my_file, "Error: Wall %i appears in two or more segments, including segment %i, side %i.\n", sidep->wall_num, i, j); else wall_flags[sidep->wall_num] = 1; } } } } //typedef struct trigger { // byte type; // short flags; // fix value; // fix time; // byte link_num; // short num_links; // short seg[MAX_WALLS_PER_LINK]; // short side[MAX_WALLS_PER_LINK]; // } trigger; // ------------------------------------------------------------------------------------------ void write_player_text(PHYSFS_file *my_file) { int i, num_players=0; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Players:\n"); for (i=0; i<=Highest_object_index; i++) { if (Objects[i].type == OBJ_PLAYER) { num_players++; PHYSFSX_printf(my_file, "Player %2i is object #%3i in segment #%3i.\n", Objects[i].id, i, Objects[i].segnum); } } #ifdef SHAREWARE if (num_players != MAX_PLAYERS) err_printf(my_file, "Error: %i player objects. %i are required.\n", num_players, MAX_PLAYERS); #endif #ifndef SHAREWARE if (num_players > MAX_MULTI_PLAYERS) err_printf(my_file, "Error: %i player objects. %i are required.\n", num_players, MAX_PLAYERS); #endif } // ------------------------------------------------------------------------------------------ void write_trigger_text(PHYSFS_file *my_file) { int i, j, w; PHYSFSX_printf(my_file, "-----------------------------------------------------------------------------\n"); PHYSFSX_printf(my_file, "Triggers:\n"); for (i=0; i 4); Assert (filename[namelen-4] == '.'); strcpy(my_filename, filename); strcpy( &my_filename[namelen-4], ".txm"); my_file = PHYSFSX_openWriteBuffered( my_filename ); if (!my_file) { char ErrorMessage[200]; sprintf( ErrorMessage, "ERROR: Unable to open output file %s\n", my_filename ); gr_palette_load(gr_palette); nm_messagebox( NULL, 1, "Ok", ErrorMessage ); return; } dump_used_textures_level(my_file, 0); say_totals(my_file, Gamesave_current_filename); PHYSFSX_printf(my_file, "\nNumber of segments: %4i\n", Highest_segment_index+1); PHYSFSX_printf(my_file, "Number of objects: %4i\n", Highest_object_index+1); PHYSFSX_printf(my_file, "Number of walls: %4i\n", Num_walls); PHYSFSX_printf(my_file, "Number of open doors: %4i\n", Num_open_doors); PHYSFSX_printf(my_file, "Number of triggers: %4i\n", Num_triggers); PHYSFSX_printf(my_file, "Number of matcens: %4i\n", Num_robot_centers); PHYSFSX_printf(my_file, "\n"); write_segment_text(my_file); write_fuelcen_text(my_file); write_matcen_text(my_file); write_player_text(my_file); write_wall_text(my_file); write_trigger_text(my_file); write_exit_text(my_file); // ---------- Find control center segment ---------- write_control_center_text(my_file); // ---------- Show keyed walls ---------- write_key_text(my_file); PHYSFS_close(my_file); } // -- // --------------- // -- // Note: This only works for a loaded level because the objects array must be valid. // -- void determine_used_textures_robots(int *tmap_buf) // -- { // -- int i, objnum; // -- polymodel *po; // -- // -- Assert(N_polygon_models); // -- // -- for (objnum=0; objnum <= Highest_object_index; objnum++) { // -- int model_num; // -- // -- if (Objects[objnum].render_type == RT_POLYOBJ) { // -- model_num = Objects[objnum].rtype.pobj_info.model_num; // -- // -- po=&Polygon_models[model_num]; // -- // -- for (i=0;in_textures;i++) { // -- int tli; // -- // -- tli = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]]; // -- Assert((tli>=0) && (tli<= Num_tmaps)); // -- tmap_buf[tli]++; // -- } // -- } // -- } // -- // -- } // ----------------------------------------------------------------------------- void determine_used_textures_level(int load_level_flag, int shareware_flag, int level_num, int *tmap_buf, int *wall_buf, sbyte *level_tmap_buf, int max_tmap) { int segnum, sidenum; int i, j; for (i=0; isides[sidenum]; if (sidep->wall_num != -1) { int clip_num = Walls[sidep->wall_num].clip_num; if (clip_num != -1) { int num_frames = WallAnims[clip_num].num_frames; wall_buf[clip_num] = 1; for (j=0; jtmap_num >= 0) { if (sidep->tmap_num < max_tmap) { tmap_buf[sidep->tmap_num]++; if (level_tmap_buf[sidep->tmap_num] == -1) level_tmap_buf[sidep->tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS; } else { Int3(); // Error, bogus texture map. Should not be greater than max_tmap. } } if ((sidep->tmap_num2 & 0x3fff) != 0) { if ((sidep->tmap_num2 & 0x3fff) < max_tmap) { tmap_buf[sidep->tmap_num2 & 0x3fff]++; if (level_tmap_buf[sidep->tmap_num2 & 0x3fff] == -1) level_tmap_buf[sidep->tmap_num2 & 0x3fff] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS; } else Int3(); // Error, bogus texture map. Should not be greater than max_tmap. } } } } // ----------------------------------------------------------------------------- void merge_buffers(int *dest, int *src, int num) { int i; for (i=0; i= 4) { PHYSFSX_printf(my_file, "\n"); count = 0; } } } // ----------------------------------------------------------------------------- void say_used_once_tmaps(PHYSFS_file *my_file, int *tb, sbyte *tb_lnum) { int i; const char *level_name; for (i=0; i= NUM_SHAREWARE_LEVELS) { Assert((level_num - NUM_SHAREWARE_LEVELS >= 0) && (level_num - NUM_SHAREWARE_LEVELS < NUM_REGISTERED_LEVELS)); level_name = Registered_level_names[level_num - NUM_SHAREWARE_LEVELS]; } else { Assert((level_num >= 0) && (level_num < NUM_SHAREWARE_LEVELS)); level_name = Shareware_level_names[level_num]; } PHYSFSX_printf(my_file, "Texture %3i %8s used only once on level %s\n", i, TmapInfo[i].filename, level_name); } } // ----------------------------------------------------------------------------- void say_unused_tmaps(PHYSFS_file *my_file, int *tb) { int i; int count = 0; for (i=0; i= 4) { PHYSFSX_printf(my_file, "\n"); count = 0; } } } // ----------------------------------------------------------------------------- void say_unused_walls(PHYSFS_file *my_file, int *tb) { int i; for (i=0; i #include #include #include #include "gr.h" #include "inferno.h" #include "game.h" #include "vclip.h" #include "effects.h" #include "bm.h" #include "u_mem.h" #include "textures.h" #include "cntrlcen.h" #include "dxxerror.h" int Num_effects; eclip Effects[MAX_EFFECTS]; void init_special_effects() { int i; for (i=0;iflags & EF_STOPPED) continue; ec->time_left -= FrameTime; while (ec->time_left < 0) { ec->time_left += ec->vc.frame_time; ec->frame_count++; if (ec->frame_count >= ec->vc.num_frames) { if (ec->flags & EF_ONE_SHOT) { Assert(ec->segnum!=-1); Assert(ec->sidenum>=0 && ec->sidenum<6); Assert(ec->dest_bm_num!=0 && Segments[ec->segnum].sides[ec->sidenum].tmap_num2!=0); Segments[ec->segnum].sides[ec->sidenum].tmap_num2 = ec->dest_bm_num | (Segments[ec->segnum].sides[ec->sidenum].tmap_num2&0xc000); //replace with destoyed ec->flags &= ~EF_ONE_SHOT; ec->segnum = -1; //done with this } ec->frame_count = 0; } } if (ec->flags & EF_CRITICAL) continue; if (ec->crit_clip!=-1 && Control_center_destroyed) { int n = ec->crit_clip; //*ec->bm_ptr = &GameBitmaps[Effects[n].vc.frames[Effects[n].frame_count].index]; if (ec->changing_wall_texture != -1) Textures[ec->changing_wall_texture] = Effects[n].vc.frames[Effects[n].frame_count]; if (ec->changing_object_texture != -1) ObjBitmaps[ec->changing_object_texture] = Effects[n].vc.frames[Effects[n].frame_count]; } else { // *ec->bm_ptr = &GameBitmaps[ec->vc.frames[ec->frame_count].index]; if (ec->changing_wall_texture != -1) Textures[ec->changing_wall_texture] = ec->vc.frames[ec->frame_count]; if (ec->changing_object_texture != -1) ObjBitmaps[ec->changing_object_texture] = ec->vc.frames[ec->frame_count]; } } } void restore_effect_bitmap_icons() { int i; for (i=0;ibm_ptr != -1); ec->flags |= EF_STOPPED; ec->frame_count = 0; //*ec->bm_ptr = &GameBitmaps[ec->vc.frames[0].index]; if (ec->changing_wall_texture != -1) Textures[ec->changing_wall_texture] = ec->vc.frames[0]; if (ec->changing_object_texture != -1) ObjBitmaps[ec->changing_object_texture] = ec->vc.frames[0]; } //restart a stopped effect void restart_effect(int effect_num) { Effects[effect_num].flags &= ~EF_STOPPED; //Assert(Effects[effect_num].bm_ptr != -1); } /* * reads n eclip structs from a PHYSFS_file */ int eclip_read_n(eclip *ec, int n, PHYSFS_file *fp) { int i, j; for (i = 0; i < n; i++) { ec[i].vc.play_time = PHYSFSX_readFix(fp); ec[i].vc.num_frames = PHYSFSX_readInt(fp); ec[i].vc.frame_time = PHYSFSX_readFix(fp); ec[i].vc.flags = PHYSFSX_readInt(fp); ec[i].vc.sound_num = PHYSFSX_readShort(fp); for (j = 0; j < VCLIP_MAX_FRAMES; j++) ec[i].vc.frames[j].index = PHYSFSX_readShort(fp); ec[i].vc.light_value = PHYSFSX_readFix(fp); ec[i].time_left = PHYSFSX_readFix(fp); ec[i].frame_count = PHYSFSX_readInt(fp); ec[i].changing_wall_texture = PHYSFSX_readShort(fp); ec[i].changing_object_texture = PHYSFSX_readShort(fp); ec[i].flags = PHYSFSX_readInt(fp); ec[i].crit_clip = PHYSFSX_readInt(fp); ec[i].dest_bm_num = PHYSFSX_readInt(fp); ec[i].dest_vclip = PHYSFSX_readInt(fp); ec[i].dest_eclip = PHYSFSX_readInt(fp); ec[i].dest_size = PHYSFSX_readFix(fp); ec[i].sound_num = PHYSFSX_readInt(fp); ec[i].segnum = PHYSFSX_readInt(fp); ec[i].sidenum = PHYSFSX_readInt(fp); } return i; } dxx-rebirth-0.58.1-d1x/main/effects.h000066400000000000000000000050551217717257200172730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Headerfile for effects.c * */ #ifndef _EFFECTS_H #define _EFFECTS_H #include "vclip.h" #define MAX_EFFECTS 60 //flags for eclips. If no flags are set, always plays #define EF_CRITICAL 1 //this doesn't get played directly (only when mine critical) #define EF_ONE_SHOT 2 //this is a special that gets played once #define EF_STOPPED 4 //this has been stopped #define ECLIP_NUM_FUELCEN 2 #define ECLIP_NUM_BOSS 53 typedef struct eclip { vclip vc; //imbedded vclip fix time_left; //for sequencing int frame_count; //for sequencing short changing_wall_texture; //Which element of Textures array to replace. short changing_object_texture; //Which element of ObjBitmapPtrs array to replace. int flags; //see above int crit_clip; //use this clip instead of above one when mine critical int dest_bm_num; //use this bitmap when monitor destroyed int dest_vclip; //what vclip to play when exploding int dest_eclip; //what eclip to play when exploding fix dest_size; //3d size of explosion int sound_num; //what sound this makes int segnum,sidenum; //what seg & side, for one-shot clips } __pack__ eclip; extern int Num_effects; extern eclip Effects[MAX_EFFECTS]; // Set up special effects. extern void init_special_effects(); // Clear any active one-shots void reset_special_effects(); // Function called in game loop to do effects. extern void do_special_effects(); // Restore bitmap extern void restore_effect_bitmap_icons(); //stop an effect from animating. Show first frame. void stop_effect(int effect_num); //restart a stopped effect void restart_effect(int effect_num); /* * reads n eclip structs from a PHYSFS_file */ extern int eclip_read_n(eclip *ec, int n, PHYSFS_file *fp); #endif /* _EFFECTS_H */ dxx-rebirth-0.58.1-d1x/main/endlevel.c000066400000000000000000001122711217717257200174440ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code for rendering external scenes * */ //#define SLEW_ON 1 //#define _MARK_ON #include //#include //This file not included in public domain release -KRB #include #include #include #include "3d.h" #include "dxxerror.h" #include "gr.h" #include "palette.h" #include "iff.h" #include "console.h" #include "texmap.h" #include "fvi.h" #include "u_mem.h" #include "sounds.h" #include "playsave.h" #include "inferno.h" #include "endlevel.h" #include "object.h" #include "game.h" #include "gauges.h" #include "wall.h" #include "terrain.h" #include "polyobj.h" #include "bm.h" #include "gameseq.h" #include "newdemo.h" #include "multi.h" #include "vclip.h" #include "render.h" #include "fireball.h" #include "text.h" #include "digi.h" #include "songs.h" #include "titles.h" #ifdef OGL #include "ogl_init.h" #endif #ifdef EDITOR #include "editor/editor.h" #endif typedef struct flythrough_data { object *obj; vms_angvec angles; //orientation in angles vms_vector step; //how far in a second vms_vector angstep; //rotation per second fix speed; //how fast object is moving vms_vector headvec; //where we want to be pointing int first_time; //flag for if first time through fix offset_frac; //how far off-center as portion of way fix offset_dist; //how far currently off-center } flythrough_data; //endlevel sequence states #define EL_OFF 0 //not in endlevel #define EL_FLYTHROUGH 1 //auto-flythrough in tunnel #define EL_LOOKBACK 2 //looking back at player #define EL_OUTSIDE 3 //flying outside for a while #define EL_STOPPED 4 //stopped, watching explosion #define EL_PANNING 5 //panning around, watching player #define EL_CHASING 6 //chasing player to station #define SHORT_SEQUENCE 1 //if defined, end sequnce when panning starts //#define STATION_ENABLED 1 //if defined, load & use space station model int Endlevel_sequence = 0; extern fix player_speed; int transition_segnum,exit_segnum; object *endlevel_camera; #define FLY_SPEED i2f(50) #define FLY_ACCEL i2f(5) fix cur_fly_speed,desired_fly_speed; extern int matt_find_connect_side(int seg0,int seg1); void generate_starfield(); void draw_stars(); int find_exit_side(object *obj); void do_endlevel_frame(); void do_endlevel_flythrough(int n); grs_bitmap *satellite_bitmap,*station_bitmap,*terrain_bitmap; //!!*exit_bitmap, vms_vector satellite_pos,satellite_upvec; //!!grs_bitmap **exit_bitmap_list[1]; int station_modelnum,exit_modelnum,destroyed_exit_modelnum; vms_vector station_pos = {0xf8c4<<10,0x3c1c<<12,0x372<<10}; #ifdef STATION_ENABLED grs_bitmap *station_bitmap; grs_bitmap **station_bitmap_list[1]; int station_modelnum; #endif vms_vector mine_exit_point; vms_vector mine_ground_exit_point; vms_vector mine_side_exit_point; vms_matrix mine_exit_orient; int outside_mine; void start_endlevel_flythrough(int n,object *obj,fix speed); grs_bitmap terrain_bm_instance; grs_bitmap satellite_bm_instance; //find delta between two angles fixang delta_ang(fixang a,fixang b) { fixang delta0,delta1; return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1; } //return though which side of seg0 is seg1 int matt_find_connect_side(int seg0,int seg1) { segment *Seg=&Segments[seg0]; int i; for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i; return -1; } void free_endlevel_data() { gr_free_bitmap_data (&terrain_bm_instance); gr_free_bitmap_data (&satellite_bm_instance); free_light_table(); free_height_array(); } void init_endlevel() { //##satellite_bitmap = bm_load("earth.bbm"); //##terrain_bitmap = bm_load("moon.bbm"); //## //##load_terrain("matt5b.bbm"); //load bitmap as height array //##//load_terrain("ttest2.bbm"); //load bitmap as height array #ifdef STATION_ENABLED station_bitmap = bm_load("steel3.bbm"); station_bitmap_list[0] = &station_bitmap; station_modelnum = load_polygon_model("station.pof",1,station_bitmap_list,NULL); #endif //!! exit_bitmap = bm_load("steel1.bbm"); //!! exit_bitmap_list[0] = &exit_bitmap; //!! exit_modelnum = load_polygon_model("exit01.pof",1,exit_bitmap_list,NULL); //!! destroyed_exit_modelnum = load_polygon_model("exit01d.pof",1,exit_bitmap_list,NULL); generate_starfield(); gr_init_bitmap_data (&terrain_bm_instance); gr_init_bitmap_data (&satellite_bm_instance); } object external_explosion; int ext_expl_playing,mine_destroyed; extern fix flash_scale; vms_angvec exit_angles={-0xa00,0,0}; vms_matrix surface_orient; int endlevel_data_loaded=0; void start_endlevel_sequence() { #ifndef NDEBUG int last_segnum; #endif int exit_side,tunnel_length; reset_rear_view(); //turn off rear view if set - NOTE: make sure this happens before we pause demo recording!! if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording Newdemo_state = ND_STATE_PAUSED; if (Newdemo_state == ND_STATE_PLAYBACK) // don't do this if in playback mode return; if (Player_is_dead || ConsoleObject->flags&OF_SHOULD_BE_DEAD) return; //don't start if dead! Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound. if (!endlevel_data_loaded) { #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_endlevel_start(0); #ifdef NETWORK multi_do_protocol_frame(1, 1); #endif } #endif PlayerFinishedLevel(0); //don't do special sequence return; } { int segnum,old_segnum,entry_side,i; //count segments in exit tunnel old_segnum = ConsoleObject->segnum; exit_side = find_exit_side(ConsoleObject); segnum = Segments[old_segnum].children[exit_side]; tunnel_length = 0; do { entry_side = matt_find_connect_side(segnum,old_segnum); exit_side = Side_opposite[entry_side]; old_segnum = segnum; segnum = Segments[segnum].children[exit_side]; tunnel_length++; } while (segnum >= 0); if (segnum != -2) { PlayerFinishedLevel(0); //don't do special sequence return; } #ifndef NDEBUG last_segnum = old_segnum; #endif //now pick transition segnum 1/3 of the way in old_segnum = ConsoleObject->segnum; exit_side = find_exit_side(ConsoleObject); segnum = Segments[old_segnum].children[exit_side]; i=tunnel_length/3; while (i--) { entry_side = matt_find_connect_side(segnum,old_segnum); exit_side = Side_opposite[entry_side]; old_segnum = segnum; segnum = Segments[segnum].children[exit_side]; } transition_segnum = segnum; } #ifndef NDEBUG Assert(last_segnum == exit_segnum); #endif #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_endlevel_start(0); multi_do_protocol_frame(1, 1); } #endif #ifndef SHAREWARE songs_play_song( SONG_ENDLEVEL, 0 ); #endif Endlevel_sequence = EL_FLYTHROUGH; ConsoleObject->movement_type = MT_NONE; //movement handled by flythrough ConsoleObject->control_type = CT_NONE; Game_suspended |= SUSP_ROBOTS; //robots don't move cur_fly_speed = desired_fly_speed = FLY_SPEED; start_endlevel_flythrough(0,ConsoleObject,cur_fly_speed); //initialize HUD_init_message_literal(HM_DEFAULT, TXT_EXIT_SEQUENCE ); outside_mine = ext_expl_playing = 0; flash_scale = f1_0; //init_endlevel(); mine_destroyed=0; } extern flythrough_data fly_objects[]; extern object *slew_obj; vms_angvec player_angles,player_dest_angles; vms_angvec camera_desired_angles,camera_cur_angles; #define CHASE_TURN_RATE (0x4000/4) //max turn per second //returns bitmask of which angles are at dest. bits 0,1,2 = p,b,h int chase_angles(vms_angvec *cur_angles,vms_angvec *desired_angles) { vms_angvec delta_angs,alt_angles,alt_delta_angs; fix total_delta,alt_total_delta; fix frame_turn; int mask=0; delta_angs.p = desired_angles->p - cur_angles->p; delta_angs.h = desired_angles->h - cur_angles->h; delta_angs.b = desired_angles->b - cur_angles->b; total_delta = abs(delta_angs.p) + abs(delta_angs.b) + abs(delta_angs.h); alt_angles.p = f1_0/2 - cur_angles->p; alt_angles.b = cur_angles->b + f1_0/2; alt_angles.h = cur_angles->h + f1_0/2; alt_delta_angs.p = desired_angles->p - alt_angles.p; alt_delta_angs.h = desired_angles->h - alt_angles.h; alt_delta_angs.b = desired_angles->b - alt_angles.b; alt_total_delta = abs(alt_delta_angs.p) + abs(alt_delta_angs.b) + abs(alt_delta_angs.h); if (alt_total_delta < total_delta) { *cur_angles = alt_angles; delta_angs = alt_delta_angs; } frame_turn = fixmul(FrameTime,CHASE_TURN_RATE); if (abs(delta_angs.p) < frame_turn) { cur_angles->p = desired_angles->p; mask |= 1; } else if (delta_angs.p > 0) cur_angles->p += frame_turn; else cur_angles->p -= frame_turn; if (abs(delta_angs.b) < frame_turn) { cur_angles->b = desired_angles->b; mask |= 2; } else if (delta_angs.b > 0) cur_angles->b += frame_turn; else cur_angles->b -= frame_turn; //cur_angles->b = 0; if (abs(delta_angs.h) < frame_turn) { cur_angles->h = desired_angles->h; mask |= 4; } else if (delta_angs.h > 0) cur_angles->h += frame_turn; else cur_angles->h -= frame_turn; return mask; } void stop_endlevel_sequence() { Interpolation_method = 0; select_cockpit(PlayerCfg.CockpitMode[0]); Endlevel_sequence = EL_OFF; PlayerFinishedLevel(0); } #define VCLIP_BIG_PLAYER_EXPLOSION 58 //--unused-- vms_vector upvec = {0,f1_0,0}; //find the angle between the player's heading & the station void get_angs_to_object(vms_angvec *av,vms_vector *targ_pos,vms_vector *cur_pos) { vms_vector tv; vm_vec_sub(&tv,targ_pos,cur_pos); vm_extract_angles_vector(av,&tv); } void do_endlevel_frame() { static fix timer; vms_vector save_last_pos; static fix explosion_wait1=0; static fix explosion_wait2=0; static fix bank_rate; static fix ext_expl_halflife; save_last_pos = ConsoleObject->last_pos; //don't let move code change this object_move_all(); ConsoleObject->last_pos = save_last_pos; if (ext_expl_playing) { external_explosion.lifeleft -= FrameTime; do_explosion_sequence(&external_explosion); if (external_explosion.lifeleft < ext_expl_halflife) mine_destroyed = 1; if (external_explosion.flags & OF_SHOULD_BE_DEAD) ext_expl_playing = 0; } if (cur_fly_speed != desired_fly_speed) { fix delta = desired_fly_speed - cur_fly_speed; fix frame_accel = fixmul(FrameTime,FLY_ACCEL); if (abs(delta) < frame_accel) cur_fly_speed = desired_fly_speed; else if (delta > 0) cur_fly_speed += frame_accel; else cur_fly_speed -= frame_accel; } //do big explosions if (!outside_mine) { if (Endlevel_sequence==EL_OUTSIDE) { vms_vector tvec; vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point); if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) { object *tobj; vms_vector mov_vec; outside_mine = 1; tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION); // Move explosion to Viewer to draw it in front of mine exit model vm_vec_normalized_dir_quick(&mov_vec,&Viewer->pos,&tobj->pos); vm_vec_scale_add2(&tobj->pos,&mov_vec,i2f(30)); if (tobj) { external_explosion = *tobj; tobj->flags |= OF_SHOULD_BE_DEAD; flash_scale = 0; //kill lights in mine ext_expl_halflife = tobj->lifeleft; ext_expl_playing = 1; } digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 ); } } //do explosions chasing player if ((explosion_wait1-=FrameTime) < 0) { vms_vector tpnt; int segnum; static int sound_count; vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-D_RAND_MAX/2)*15); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-D_RAND_MAX/2)*15); segnum = find_point_seg(&tpnt,ConsoleObject->segnum); if (segnum != -1) { object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION); if (d_rand()<10000 || ++sound_count==7) { //pseudo-random digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 ); sound_count=0; } } explosion_wait1 = 0x2000 + d_rand()/4; } } //do little explosions on walls if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE) if ((explosion_wait2-=FrameTime) < 0) { vms_vector tpnt; fvi_query fq; fvi_info hit_data; //create little explosion on wall vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-D_RAND_MAX/2)*100); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-D_RAND_MAX/2)*100); vm_vec_add2(&tpnt,&ConsoleObject->pos); if (Endlevel_sequence == EL_FLYTHROUGH) vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*200); else vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*60); //find hit point on wall fq.p0 = &ConsoleObject->pos; fq.p1 = &tpnt; fq.startseg = ConsoleObject->segnum; fq.rad = 0; fq.thisobjnum = 0; fq.ignore_obj_list = NULL; fq.flags = 0; find_vector_intersection(&fq,&hit_data); if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1) object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+d_rand()*6,VCLIP_SMALL_EXPLOSION); explosion_wait2 = (0xa00 + d_rand()/8)/2; } switch (Endlevel_sequence) { case EL_OFF: return; case EL_FLYTHROUGH: { do_endlevel_flythrough(0); if (ConsoleObject->segnum == transition_segnum) { int objnum; Endlevel_sequence = EL_LOOKBACK; objnum = obj_create(OBJ_CAMERA, 0, ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0, CT_NONE,MT_NONE,RT_NONE); if (objnum == -1) { //can't get object, so abort con_printf(CON_DEBUG, "Can't get object for endlevel sequence. Aborting endlevel sequence.\n"); stop_endlevel_sequence(); return; } Viewer = endlevel_camera = &Objects[objnum]; select_cockpit(CM_LETTERBOX); fly_objects[1] = fly_objects[0]; fly_objects[1].obj = endlevel_camera; fly_objects[1].speed = (5*cur_fly_speed)/4; fly_objects[1].offset_frac = 0x4000; vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7)); timer=0x20000; } break; } case EL_LOOKBACK: { do_endlevel_flythrough(0); do_endlevel_flythrough(1); if (timer>0) { timer -= FrameTime; if (timer < 0) //reduce speed fly_objects[1].speed = fly_objects[0].speed; } if (endlevel_camera->segnum == exit_segnum) { vms_angvec cam_angles,exit_seg_angles; Endlevel_sequence = EL_OUTSIDE; timer = i2f(2); vm_vec_negate(&endlevel_camera->orient.fvec); vm_vec_negate(&endlevel_camera->orient.rvec); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient); bank_rate = (-exit_seg_angles.b - cam_angles.b)/2; ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE; //_MARK_("Starting outside");//Commented out by KRB #ifdef SLEW_ON slew_obj = endlevel_camera; #endif } break; } case EL_OUTSIDE: { #ifndef SLEW_ON vms_angvec cam_angles; #endif vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed)); vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10)); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); cam_angles.b += fixmul(bank_rate,FrameTime); vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles); #endif timer -= FrameTime; if (timer < 0) { Endlevel_sequence = EL_STOPPED; vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient); timer = i2f(3); } break; } case EL_STOPPED: { get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); timer -= FrameTime; if (timer < 0) { #ifdef SLEW_ON slew_obj = endlevel_camera; _do_slew_movement(endlevel_camera,1); timer += FrameTime; //make time stop break; #else #ifdef SHORT_SEQUENCE stop_endlevel_sequence(); #else Endlevel_sequence = EL_PANNING; vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient); timer = i2f(3); if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer stop_endlevel_sequence(); return; } #endif //SHORT_SEQUENCE #endif //SLEW_ON } break; } #ifndef SHORT_SEQUENCE case EL_PANNING: { #ifndef SLEW_ON int mask; #endif get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1); #else get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); mask = chase_angles(&camera_cur_angles,&camera_desired_angles); vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); if ((mask&5) == 5) { vms_vector tvec; Endlevel_sequence = EL_CHASING; //_MARK_("Done outside");//Commented out -KRB vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos); vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL); desired_fly_speed *= 2; } #endif break; } case EL_CHASING: { fix d,speed_scale; #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1); #endif get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); chase_angles(&camera_cur_angles,&camera_desired_angles); #ifndef SLEW_ON vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); #endif d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos); speed_scale = fixdiv(d,i2f(0x20)); if (dpos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed))); if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10)) stop_endlevel_sequence(); #endif break; } #endif //ifdef SHORT_SEQUENCE } } #define MIN_D 0x100 //find which side to fly out of int find_exit_side(object *obj) { int i; vms_vector prefvec,segcenter,sidevec; fix best_val=-f2_0; int best_side; segment *pseg = &Segments[obj->segnum]; //find exit side vm_vec_normalized_dir_quick(&prefvec,&obj->pos,&obj->last_pos); compute_segment_center(&segcenter,pseg); best_side=-1; for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) { fix d; if (pseg->children[i]!=-1) { compute_center_point_on_side(&sidevec,pseg,i); vm_vec_normalized_dir_quick(&sidevec,&sidevec,&segcenter); d = vm_vec_dotprod(&sidevec,&prefvec); if (labs(d) < MIN_D) d=0; if (d > best_val) {best_val=d; best_side=i;} } } Assert(best_side!=-1); return best_side; } extern fix Render_zoom; //the player's zoom factor extern vms_vector Viewer_eye; //valid during render void draw_exit_model() { vms_vector model_pos; int f=15,u=0; //21; g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; vm_vec_scale_add(&model_pos,&mine_exit_point,&mine_exit_orient.fvec,i2f(f)); vm_vec_scale_add2(&model_pos,&mine_exit_orient.uvec,i2f(u)); draw_polygon_model(&model_pos,&mine_exit_orient,NULL,(mine_destroyed)?destroyed_exit_modelnum:exit_modelnum,0,lrgb,NULL,NULL); } int exit_point_bmx,exit_point_bmy; fix satellite_size = i2f(400); #define SATELLITE_DIST i2f(1024) #define SATELLITE_WIDTH satellite_size #define SATELLITE_HEIGHT ((satellite_size*9)/4) //((satellite_size*5)/2) void render_external_scene(fix eye_offset) { #ifdef OGL int orig_Render_depth = Render_depth; #endif g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; Viewer_eye = Viewer->pos; if (eye_offset) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset); g3_set_view_matrix(&Viewer->pos,&Viewer->orient,Render_zoom); //g3_draw_horizon(BM_XRGB(0,0,0),BM_XRGB(16,16,16)); //,-1); gr_clear_canvas(BM_XRGB(0,0,0)); g3_start_instance_matrix(&vmd_zero_vector,&surface_orient); draw_stars(); g3_done_instance(); { //draw satellite vms_vector delta; g3s_point p,top_pnt; g3_rotate_point(&p,&satellite_pos); g3_rotate_delta_vec(&delta,&satellite_upvec); g3_add_delta_vec(&top_pnt,&p,&delta); if (! (p.p3_codes & CC_BEHIND)) { int save_im = Interpolation_method; //p.p3_flags &= ~PF_PROJECTED; //g3_project_point(&p); if (! (p.p3_flags & PF_OVERFLOW)) { Interpolation_method = 0; //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap); g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,lrgb); Interpolation_method = save_im; } } } #ifdef STATION_ENABLED draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,lrgb,NULL,NULL); #endif #ifdef OGL ogl_toggle_depth_test(0); Render_depth = (200-(vm_vec_dist_quick(&mine_ground_exit_point, &Viewer_eye)/F1_0))/36; #endif render_terrain(&mine_ground_exit_point,exit_point_bmx,exit_point_bmy); #ifdef OGL Render_depth = orig_Render_depth; ogl_toggle_depth_test(1); #endif draw_exit_model(); if (ext_expl_playing) { if ( PlayerCfg.AlphaEffects ) // set nice transparency/blending for the big explosion gr_settransblend( GR_FADE_OFF, GR_BLEND_ADDITIVE_C ); draw_fireball(&external_explosion); gr_settransblend( GR_FADE_OFF, GR_BLEND_NORMAL ); // revert any transparency/blending setting back to normal } Lighting_on=0; render_object(ConsoleObject); Lighting_on=1; } #define MAX_STARS 500 vms_vector stars[MAX_STARS]; void generate_starfield() { int i; for (i=0;ipos; if (Viewer->type == OBJ_PLAYER ) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4); if (eye_offset) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset); #ifdef EDITOR if (EditorWindow) Viewer_eye = Viewer->pos; #endif if (Endlevel_sequence >= EL_OUTSIDE) { start_seg_num = exit_segnum; } else { start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum); if (start_seg_num==-1) start_seg_num = Viewer->segnum; } if (Endlevel_sequence == EL_LOOKBACK) { vms_matrix headm,viewm; vms_angvec angles = {0,0,0x7fff}; vm_angles_2_matrix(&headm,&angles); vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm); g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom); } else g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom); render_mine(start_seg_num,eye_offset); } void render_endlevel_frame(fix eye_offset) { g3_start_frame(); if (Endlevel_sequence < EL_OUTSIDE) endlevel_render_mine(eye_offset); else render_external_scene(eye_offset); g3_end_frame(); } ///////////////////////// copy of flythrough code for endlevel #define MAX_FLY_OBJECTS 2 flythrough_data fly_objects[MAX_FLY_OBJECTS]; flythrough_data *flydata; int matt_find_connect_side(int seg0,int seg1); void compute_segment_center(vms_vector *vp,segment *sp); fixang delta_ang(fixang a,fixang b); fixang interp_angle(fixang dest,fixang src,fixang step); #define DEFAULT_SPEED i2f(16) #define MIN_D 0x100 //if speed is zero, use default speed void start_endlevel_flythrough(int n,object *obj,fix speed) { flydata = &fly_objects[n]; flydata->obj = obj; flydata->first_time = 1; flydata->speed = speed?speed:DEFAULT_SPEED; flydata->offset_frac = 0; } static vms_angvec *angvec_add2_scale(vms_angvec *dest,vms_vector *src,fix s) { dest->p += fixmul(src->x,s); dest->b += fixmul(src->z,s); dest->h += fixmul(src->y,s); return dest; } #define MAX_ANGSTEP 0x4000 //max turn per second #define MAX_SLIDE_PER_SEGMENT 0x10000 void do_endlevel_flythrough(int n) { object *obj; segment *pseg; int old_player_seg; flydata = &fly_objects[n]; obj = flydata->obj; old_player_seg = obj->segnum; //move the player for this frame if (!flydata->first_time) { vm_vec_scale_add2(&obj->pos,&flydata->step,FrameTime); angvec_add2_scale(&flydata->angles,&flydata->angstep,FrameTime); vm_angles_2_matrix(&obj->orient,&flydata->angles); } //check new player seg update_object_seg(obj); pseg = &Segments[obj->segnum]; if (flydata->first_time || obj->segnum != old_player_seg) { //moved into new seg vms_vector curcenter,nextcenter; fix step_size,seg_time; short entry_side,exit_side = -1;//what sides we entry and leave through vms_vector dest_point; //where we are heading (center of exit_side) vms_angvec dest_angles; //where we want to be pointing vms_matrix dest_orient; int up_side=0; entry_side=0; //find new exit side if (!flydata->first_time) { entry_side = matt_find_connect_side(obj->segnum,old_player_seg); exit_side = Side_opposite[entry_side]; } if (flydata->first_time || entry_side==-1 || pseg->children[exit_side]==-1) exit_side = find_exit_side(obj); { //find closest side to align to fix d,largest_d=-f1_0; int i; for (i=0;i<6;i++) { #ifdef COMPACT_SEGS vms_vector v1; get_side_normal(pseg, i, 0, &v1 ); d = vm_vec_dot(&v1,&flydata->obj->orient.uvec); #else d = vm_vec_dot(&pseg->sides[i].normals[0],&flydata->obj->orient.uvec); #endif if (d > largest_d) {largest_d = d; up_side=i;} } } //update target point & angles compute_center_point_on_side(&dest_point,pseg,exit_side); if (pseg->children[exit_side] == -2) nextcenter = dest_point; else compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]); //update target point and movement points //offset object sideways if (flydata->offset_frac) { int s0=-1,s1=0,i; vms_vector s0p,s1p; fix dist; for (i=0;i<6;i++) if (i!=entry_side && i!=exit_side && i!=up_side && i!=Side_opposite[up_side]) { if (s0==-1) s0 = i; else s1 = i; } compute_center_point_on_side(&s0p,pseg,s0); compute_center_point_on_side(&s1p,pseg,s1); dist = fixmul(vm_vec_dist(&s0p,&s1p),flydata->offset_frac); if (dist-flydata->offset_dist > MAX_SLIDE_PER_SEGMENT) dist = flydata->offset_dist + MAX_SLIDE_PER_SEGMENT; flydata->offset_dist = dist; vm_vec_scale_add2(&dest_point,&obj->orient.rvec,dist); } vm_vec_sub(&flydata->step,&dest_point,&obj->pos); step_size = vm_vec_normalize_quick(&flydata->step); vm_vec_scale(&flydata->step,flydata->speed); compute_segment_center(&curcenter,pseg); vm_vec_sub(&flydata->headvec,&nextcenter,&curcenter); #ifdef COMPACT_SEGS { vms_vector _v1; get_side_normal(pseg, up_side, 0, &_v1 ); vm_vector_2_matrix(&dest_orient,&flydata->headvec,&_v1,NULL); } #else vm_vector_2_matrix(&dest_orient,&flydata->headvec,&pseg->sides[up_side].normals[0],NULL); #endif vm_extract_angles_matrix(&dest_angles,&dest_orient); if (flydata->first_time) vm_extract_angles_matrix(&flydata->angles,&obj->orient); seg_time = fixdiv(step_size,flydata->speed); //how long through seg if (seg_time) { flydata->angstep.x = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.p,dest_angles.p),seg_time))); flydata->angstep.z = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.b,dest_angles.b),seg_time))); flydata->angstep.y = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.h,dest_angles.h),seg_time))); } else { flydata->angles = dest_angles; flydata->angstep.x = flydata->angstep.y = flydata->angstep.z = 0; } } flydata->first_time=0; } #define JOY_NULL 15 #define ROT_SPEED 8 //rate of rotation while key held down #define VEL_SPEED (15) //rate of acceleration while key held down extern short old_joy_x,old_joy_y; //position last time around #include "key.h" #include "joy.h" #ifdef SLEW_ON //this is a special routine for slewing around external scene int _do_slew_movement(object *obj, int check_keys ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; vms_angvec rotang; if (keyd_pressed[KEY_PAD5]) vm_vec_zero(&obj->phys_info.velocity); if (check_keys) { obj->phys_info.velocity.x += VEL_SPEED * keyd_pressed[KEY_PAD9] * FrameTime; obj->phys_info.velocity.x -= VEL_SPEED * keyd_pressed[KEY_PAD7] * FrameTime; obj->phys_info.velocity.y += VEL_SPEED * keyd_pressed[KEY_PADMINUS] * FrameTime; obj->phys_info.velocity.y -= VEL_SPEED * keyd_pressed[KEY_PADPLUS] * FrameTime; obj->phys_info.velocity.z += VEL_SPEED * keyd_pressed[KEY_PAD8] * FrameTime; obj->phys_info.velocity.z -= VEL_SPEED * keyd_pressed[KEY_PAD2] * FrameTime; rotang.pitch = rotang.bank = rotang.head = 0; rotang.pitch += keyd_pressed[KEY_LBRACKET] * FrameTime / ROT_SPEED; rotang.pitch -= keyd_pressed[KEY_RBRACKET] * FrameTime / ROT_SPEED; rotang.bank += keyd_pressed[KEY_PAD1] * FrameTime / ROT_SPEED; rotang.bank -= keyd_pressed[KEY_PAD3] * FrameTime / ROT_SPEED; rotang.head += keyd_pressed[KEY_PAD6] * FrameTime / ROT_SPEED; rotang.head -= keyd_pressed[KEY_PAD4] * FrameTime / ROT_SPEED; } else rotang.pitch = rotang.bank = rotang.head = 0; moved = rotang.pitch | rotang.bank | rotang.head; vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; vm_transpose_matrix(&new_pm); //make those columns rows moved |= obj->phys_info.velocity.x | obj->phys_info.velocity.y | obj->phys_info.velocity.z; svel = obj->phys_info.velocity; vm_vec_scale(&svel,FrameTime); //movement in this frame vm_vec_rotate(&movement,&svel,&new_pm); vm_vec_add2(&obj->pos,&movement); moved |= (movement.x || movement.y || movement.z); return moved; } #endif #define LINE_LEN 80 #define NUM_VARS 8 #define STATION_DIST i2f(1024) int convert_ext( char *dest, char *ext ) { char *t; t = strchr(dest,'.'); if (t && (t-dest <= 8)) { t[1] = ext[0]; t[2] = ext[1]; t[3] = ext[2]; return 1; } else return 0; } //called for each level to load & setup the exit sequence void load_endlevel_data(int level_num) { char filename[13]; char line[LINE_LEN],*p; PHYSFS_file *ifile; int var,segnum,sidenum; int exit_side = 0; int have_binary = 0; endlevel_data_loaded = 0; //not loaded yet try_again: ; #ifdef SHAREWARE sprintf(filename,"level%02d.sdl", level_num); #else if (level_num<0) //secret level strcpy(filename,Secret_level_names[-level_num-1]); else //normal level strcpy(filename,Level_names[level_num-1]); #endif if (!convert_ext(filename,"end")) return; ifile = PHYSFSX_openReadBuffered(filename); if (!ifile) { convert_ext(filename,"txb"); if (!strcmp(filename, Briefing_text_filename) || !strcmp(filename, Ending_text_filename)) return; // Don't want to interpret the briefing as an end level sequence! ifile = PHYSFSX_openReadBuffered(filename); if (!ifile) { if (level_num==1) { return; //abort //Error("Cannot load file text of binary version of <%s>",filename); } else { level_num = 1; goto try_again; } } have_binary = 1; } //ok...this parser is pretty simple. It ignores comments, but //everything else must be in the right place var = 0; while (PHYSFSX_fgets(line,LINE_LEN,ifile)) { if (have_binary) decode_text_line (line); if ((p=strchr(line,';'))!=NULL) *p = 0; //cut off comment for (p=line+strlen(line)-1;p>line && isspace(*p);*p--=0); for (p=line;isspace(*p);p++); if (!*p) //empty line continue; switch (var) { case 0: { //ground terrain int iff_error; ubyte pal[768]; gr_free_bitmap_data (&terrain_bm_instance); iff_error = iff_read_bitmap(p,&terrain_bm_instance,BM_LINEAR,pal); if (iff_error != IFF_NO_ERROR) { con_printf(CON_DEBUG, "Can't load exit terrain from file %s: IFF error: %s\n", p, iff_errormsg(iff_error)); endlevel_data_loaded = 0; // won't be able to play endlevel sequence PHYSFS_close(ifile); return; } terrain_bitmap = &terrain_bm_instance; gr_remap_bitmap_good( terrain_bitmap, pal, iff_transparent_color, -1); break; } case 1: //height map load_terrain(p); break; case 2: sscanf(p,"%d,%d",&exit_point_bmx,&exit_point_bmy); break; case 3: //exit heading exit_angles.h = i2f(atoi(p))/360; break; case 4: { //planet bitmap int iff_error; ubyte pal[768]; gr_free_bitmap_data (&satellite_bm_instance); iff_error = iff_read_bitmap(p,&satellite_bm_instance,BM_LINEAR,pal); if (iff_error != IFF_NO_ERROR) { con_printf(CON_DEBUG, "Can't load exit satellite from file %s: IFF error: %s\n", p, iff_errormsg(iff_error)); endlevel_data_loaded = 0; // won't be able to play endlevel sequence PHYSFS_close(ifile); return; } satellite_bitmap = &satellite_bm_instance; gr_remap_bitmap_good( satellite_bitmap, pal, iff_transparent_color, -1); break; } case 5: //earth pos case 7: { //station pos vms_matrix tm; vms_angvec ta; int pitch,head; sscanf(p,"%d,%d",&head,&pitch); ta.h = i2f(head)/360; ta.p = -i2f(pitch)/360; ta.b = 0; vm_angles_2_matrix(&tm,&ta); if (var==5) satellite_pos = tm.fvec; //vm_vec_copy_scale(&satellite_pos,&tm.fvec,SATELLITE_DIST); else station_pos = tm.fvec; break; } case 6: //planet size satellite_size = i2f(atoi(p)); break; } var++; } Assert(var == NUM_VARS); // OK, now the data is loaded. Initialize everything //find the exit sequence by searching all segments for a side with //children == -2 for (segnum=0,exit_segnum=-1;exit_segnum==-1 && segnum<=Highest_segment_index;segnum++) for (sidenum=0;sidenum<6;sidenum++) if (Segments[segnum].children[sidenum] == -2) { exit_segnum = segnum; exit_side = sidenum; break; } Assert(exit_segnum!=-1); compute_segment_center(&mine_exit_point,&Segments[exit_segnum]); extract_orient_from_segment(&mine_exit_orient,&Segments[exit_segnum]); compute_center_point_on_side(&mine_side_exit_point,&Segments[exit_segnum],exit_side); vm_vec_scale_add(&mine_ground_exit_point,&mine_exit_point,&mine_exit_orient.uvec,-i2f(20)); //compute orientation of surface { vms_vector tv; vms_matrix exit_orient,tm; vm_angles_2_matrix(&exit_orient,&exit_angles); vm_transpose_matrix(&exit_orient); vm_matrix_x_matrix(&surface_orient,&mine_exit_orient,&exit_orient); vm_copy_transpose_matrix(&tm,&surface_orient); vm_vec_rotate(&tv,&station_pos,&tm); vm_vec_scale_add(&station_pos,&mine_exit_point,&tv,STATION_DIST); vm_vec_rotate(&tv,&satellite_pos,&tm); vm_vec_scale_add(&satellite_pos,&mine_exit_point,&tv,SATELLITE_DIST); vm_vector_2_matrix(&tm,&tv,&surface_orient.uvec,NULL); vm_vec_copy_scale(&satellite_upvec,&tm.uvec,SATELLITE_HEIGHT); } PHYSFS_close(ifile); endlevel_data_loaded = 1; } dxx-rebirth-0.58.1-d1x/main/endlevel.h000066400000000000000000000026721217717257200174540ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for endlevel.c * */ #ifndef _OUTSIDE_H #define _OUTSIDE_H #include "object.h" extern int Endlevel_sequence; void start_endlevel_sequence(); void render_external_scene(); void render_endlevel_frame(fix eye_offset); void do_endlevel_frame(); void draw_exit_model(); void free_endlevel_data(); void init_endlevel(); void stop_endlevel_sequence(); extern vms_vector mine_exit_point; extern int exit_segnum; extern grs_bitmap *satellite_bitmap,*station_bitmap,*exit_bitmap,*terrain_bitmap; extern object external_explosion; extern int ext_expl_playing; //called for each level to load & setup the exit sequence void load_endlevel_data(int level_num); extern int exit_modelnum, destroyed_exit_modelnum; #endif dxx-rebirth-0.58.1-d1x/main/fireball.c000066400000000000000000001113761217717257200174330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code for rendering & otherwise dealing with explosions * */ #include #include #include #include "dxxerror.h" #include "3d.h" #include "inferno.h" #include "object.h" #include "vclip.h" #include "game.h" #include "polyobj.h" #include "sounds.h" #include "player.h" #include "gauges.h" #include "powerup.h" #include "bm.h" #include "ai.h" #include "weapon.h" #include "fireball.h" #include "collide.h" #include "newmenu.h" #include "gameseq.h" #include "physics.h" #include "scores.h" #include "laser.h" #include "wall.h" #include "multi.h" #include "endlevel.h" #include "timer.h" #include "fuelcen.h" #include "cntrlcen.h" #include "gameseg.h" #define EXPLOSION_SCALE fl2f(2.5) //explosion is the obj size times this //--unused-- ubyte Frame_processed[MAX_OBJECTS]; object *object_create_explosion_sub(object *objp, short segnum, vms_vector * position, fix size, int vclip_type, fix maxdamage, fix maxdistance, fix maxforce, int parent ) { int objnum; object *obj; objnum = obj_create( OBJ_FIREBALL,vclip_type,segnum,position,&vmd_identity_matrix,size, CT_EXPLOSION,MT_NONE,RT_FIREBALL); if (objnum < 0 ) { return NULL; } obj = &Objects[objnum]; //now set explosion-specific data obj->lifeleft = Vclip[vclip_type ].play_time; obj->ctype.expl_info.spawn_time = -1; obj->ctype.expl_info.delete_objnum = -1; obj->ctype.expl_info.delete_time = -1; if (maxdamage > 0) { fix dist, force; vms_vector pos_hit, vforce; fix damage; int i; object * obj0p = &Objects[0]; // -- now legal for badass explosions on a wall. Assert(objp != NULL); for (i=0; i<=Highest_object_index; i++ ) { sbyte parent_check = 0; // Weapons used to be affected by badass explosions, but this introduces serious problems. // When a smart bomb blows up, if one of its children goes right towards a nearby wall, it will // blow up, blowing up all the children. So I remove it. MK, 09/11/94 if (parent != -1) if ((Objects[parent].type != OBJ_ROBOT) || (Objects[parent].id != obj0p->id)) parent_check = 1; if ( (obj0p->type == OBJ_CNTRLCEN) || (obj0p->type==OBJ_PLAYER) || ((obj0p->type==OBJ_ROBOT) && parent_check)) { dist = vm_vec_dist_quick( &obj0p->pos, &obj->pos ); // Make damage be from 'maxdamage' to 0.0, where 0.0 is 'maxdistance' away; if ( dist < maxdistance ) { if (object_to_object_visibility(obj, obj0p, FQ_TRANSWALL)) { damage = maxdamage - fixmuldiv( dist, maxdamage, maxdistance ); force = maxforce - fixmuldiv( dist, maxforce, maxdistance ); // Find the force vector on the object vm_vec_sub( &vforce, &obj0p->pos, &obj->pos ); vm_vec_normalize_quick(&vforce); vm_vec_scale(&vforce, force ); // Find where the point of impact is... ( pos_hit ) vm_vec_scale(vm_vec_sub(&pos_hit, &obj->pos, &obj0p->pos), fixdiv(obj0p->size, obj0p->size + dist)); switch ( obj0p->type ) { case OBJ_ROBOT: phys_apply_force(obj0p,&vforce); // When a robot gets whacked by a badass force, he looks towards it because robots tend to get blasted from behind. { vms_vector neg_vforce; neg_vforce.x = vforce.x * -2 * (7 - Difficulty_level)/8; neg_vforce.y = vforce.y * -2 * (7 - Difficulty_level)/8; neg_vforce.z = vforce.z * -2 * (7 - Difficulty_level)/8; phys_apply_rot(obj0p,&neg_vforce); } if ( obj0p->shields >= 0 ) { if (apply_damage_to_robot(obj0p, damage, parent)) if ((objp != NULL) && (parent == Players[Player_num].objnum)) add_points_to_score(Robot_info[obj0p->id].score_value); } break; case OBJ_CNTRLCEN: if ( obj0p->shields >= 0 ) { apply_damage_to_controlcen(obj0p, damage, parent ); } break; case OBJ_PLAYER: { object * killer=NULL; vms_vector vforce2; if ((objp != NULL) && (Game_mode & GM_MULTI) && (objp->type == OBJ_PLAYER)) { killer = objp; } vforce2 = vforce; if (parent > -1 ) { killer = &Objects[parent]; if (killer != ConsoleObject) // if someone else whacks you, cut force by 2x vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; } vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; phys_apply_force(obj0p,&vforce); phys_apply_rot(obj0p,&vforce2); if ( obj0p->shields >= 0 ) apply_damage_to_player(obj0p, killer, damage, 0 ); } break; default: Int3(); // Illegal object type } // end switch } else { ; } // end if (object_to_object_visibility... } // end if (dist < maxdistance) } obj0p++; } // end for } // end if (maxdamage... return obj; } object *object_create_muzzle_flash(short segnum, vms_vector * position, fix size, int vclip_type ) { return object_create_explosion_sub(NULL, segnum, position, size, vclip_type, 0, 0, 0, -1 ); } object *object_create_explosion(short segnum, vms_vector * position, fix size, int vclip_type ) { return object_create_explosion_sub(NULL, segnum, position, size, vclip_type, 0, 0, 0, -1 ); } object *object_create_badass_explosion(object *objp, short segnum, vms_vector * position, fix size, int vclip_type, fix maxdamage, fix maxdistance, fix maxforce, int parent ) { object *rval; rval = object_create_explosion_sub(objp, segnum, position, size, vclip_type, maxdamage, maxdistance, maxforce, parent ); if ((objp != NULL) && (objp->type == OBJ_WEAPON)) #define NUM_SMART_CHILDREN 6 create_smart_children(objp, NUM_SMART_CHILDREN); return rval; } //blows up a badass weapon, creating the badass explosion //return the explosion object object *explode_badass_weapon(object *obj) { weapon_info *wi = &Weapon_info[obj->id]; Assert(wi->damage_radius); digi_link_sound_to_object(SOUND_BADASS_EXPLOSION, obj-Objects, 0, F1_0); return object_create_badass_explosion( obj, obj->segnum, &obj->pos, wi->impact_size, wi->robot_hit_vclip, wi->strength[Difficulty_level], wi->damage_radius,wi->strength[Difficulty_level], obj->ctype.laser_info.parent_num); } object *explode_badass_object(object *objp, fix damage, fix distance, fix force) { object *rval; rval = object_create_badass_explosion(objp, objp->segnum, &objp->pos, objp->size, get_explosion_vclip(objp, 0), damage, distance, force, objp-Objects); if (rval) digi_link_sound_to_object(SOUND_BADASS_EXPLOSION, rval-Objects, 0, F1_0); return (rval); } //blows up the player with a badass explosion //return the explosion object object *explode_badass_player(object *objp) { return explode_badass_object(objp, F1_0*50, F1_0*40, F1_0*150); } #define DEBRIS_LIFE (f1_0 * (PERSISTENT_DEBRIS?60:2)) //lifespan in seconds object *object_create_debris(object *parent, int subobj_num) { int objnum; object *obj; Assert((parent->type == OBJ_ROBOT) || (parent->type == OBJ_PLAYER) ); objnum = obj_create(OBJ_DEBRIS,0,parent->segnum,&parent->pos, &parent->orient,Polygon_models[parent->rtype.pobj_info.model_num].submodel_rads[subobj_num], CT_DEBRIS,MT_PHYSICS,RT_POLYOBJ); if ((objnum < 0 ) && (Highest_object_index >= MAX_OBJECTS-1)) { Int3(); return NULL; } if ( objnum < 0 ) return NULL; // Not enough debris slots! obj = &Objects[objnum]; Assert(subobj_num < 32); //Set polygon-object-specific data obj->rtype.pobj_info.model_num = parent->rtype.pobj_info.model_num; obj->rtype.pobj_info.subobj_flags = 1<rtype.pobj_info.tmap_override = parent->rtype.pobj_info.tmap_override; //Set physics data for this object obj->mtype.phys_info.velocity.x = D_RAND_MAX/2 - d_rand(); obj->mtype.phys_info.velocity.y = D_RAND_MAX/2 - d_rand(); obj->mtype.phys_info.velocity.z = D_RAND_MAX/2 - d_rand(); vm_vec_normalize_quick(&obj->mtype.phys_info.velocity); vm_vec_scale(&obj->mtype.phys_info.velocity,i2f(10 + (30 * d_rand() / D_RAND_MAX))); vm_vec_add2(&obj->mtype.phys_info.velocity,&parent->mtype.phys_info.velocity); // -- used to be: Notice, not random! vm_vec_make(&obj->mtype.phys_info.rotvel,10*0x2000/3,10*0x4000/3,10*0x7000/3); vm_vec_make(&obj->mtype.phys_info.rotvel, d_rand() + 0x1000, d_rand()*2 + 0x4000, d_rand()*3 + 0x2000); vm_vec_zero(&obj->mtype.phys_info.rotthrust); obj->lifeleft = 3*DEBRIS_LIFE/4 + fixmul(d_rand(), DEBRIS_LIFE); // Some randomness, so they don't all go away at the same time. obj->mtype.phys_info.mass = fixmuldiv(parent->mtype.phys_info.mass,obj->size,parent->size); obj->mtype.phys_info.drag = 0; //fl2f(0.2); //parent->mtype.phys_info.drag; if (PERSISTENT_DEBRIS) { obj->mtype.phys_info.flags |= PF_BOUNCE; obj->mtype.phys_info.drag = 128; } return obj; } void draw_fireball(object *obj) { if ( obj->lifeleft > 0 ) draw_vclip_object(obj,obj->lifeleft,0, obj->id); } // -------------------------------------------------------------------------------------------------------------------- // Return true if there is a door here and it is openable // It is assumed that the player has all keys. int door_is_openable_by_player(segment *segp, int sidenum) { int wall_num, wall_type; wall_num = segp->sides[sidenum].wall_num; wall_type = Walls[wall_num].type; if (wall_num == -1) return 0; // no wall here. // Can't open locked doors. if (((wall_type == WALL_DOOR) && (Walls[wall_num].flags & WALL_DOOR_LOCKED)) || (wall_type == WALL_CLOSED)) return 0; return 1; } #define QUEUE_SIZE 64 // -------------------------------------------------------------------------------------------------------------------- // Return a segment %i segments away from initial segment. // Returns -1 if can't find a segment that distance away. int pick_connected_segment(object *objp, int max_depth) { int i; int cur_depth; int start_seg; int head, tail; int seg_queue[QUEUE_SIZE*2]; sbyte visited[MAX_SEGMENTS]; sbyte depth[MAX_SEGMENTS]; sbyte side_rand[MAX_SIDES_PER_SEGMENT]; memset(visited, 0, Highest_segment_index+1); memset(depth, 0, Highest_segment_index+1); memset(seg_queue,0,QUEUE_SIZE*2); start_seg = objp->segnum; head = 0; tail = 0; seg_queue[head++] = start_seg; cur_depth = 0; for (i=0; i> 15; temp = side_rand[ind1]; side_rand[ind1] = side_rand[i]; side_rand[i] = temp; } while (tail != head) { int sidenum, count; segment *segp; int ind1, ind2, temp; if (cur_depth >= max_depth) { return seg_queue[tail]; } segp = &Segments[seg_queue[tail++]]; tail &= QUEUE_SIZE-1; // to make random, switch a pair of entries in side_rand. ind1 = (d_rand() * MAX_SIDES_PER_SEGMENT) >> 15; ind2 = (d_rand() * MAX_SIDES_PER_SEGMENT) >> 15; temp = side_rand[ind1]; side_rand[ind1] = side_rand[ind2]; side_rand[ind2] = temp; count = 0; for (sidenum=ind1; countsides[snrand].wall_num; sidenum++; if ((wall_num == -1 || door_is_openable_by_player(segp, snrand)) && segp->children[snrand] > -1) { if (visited[segp->children[snrand]] == 0) { seg_queue[head++] = segp->children[snrand]; visited[segp->children[snrand]] = 1; depth[segp->children[snrand]] = cur_depth+1; head &= QUEUE_SIZE-1; if (head > tail) { if (head == tail + QUEUE_SIZE-1) Int3(); // queue overflow. Make it bigger! } else if (head+QUEUE_SIZE == tail + QUEUE_SIZE-1) Int3(); // queue overflow. Make it bigger! } } } if ((seg_queue[tail] < 0) || (seg_queue[tail] > Highest_segment_index)) { // -- Int3(); // Something bad has happened. Queue is trashed. --MK, 12/13/94 return -1; } cur_depth = depth[seg_queue[tail]]; } return -1; } #define BASE_NET_DROP_DEPTH 10 // ------------------------------------------------------------------------------------------------------ // Choose segment to drop a powerup in. // For all active net players, try to create a N segment path from the player. If possible, return that // segment. If not possible, try another player. After a few tries, use a random segment. // Don't drop if control center in segment. int choose_drop_segment() { int pnum = 0; int segnum = -1; int cur_drop_depth; int count; int player_seg; vms_vector tempv,*player_pos; d_srand((fix)timer_query()); cur_drop_depth = BASE_NET_DROP_DEPTH + ((d_rand() * BASE_NET_DROP_DEPTH*2) >> 15); player_pos = &Objects[Players[Player_num].objnum].pos; player_seg = Objects[Players[Player_num].objnum].segnum; while ((segnum == -1) && (cur_drop_depth > BASE_NET_DROP_DEPTH/2)) { pnum = (d_rand() * N_players) >> 15; count = 0; while ((count < N_players) && ((Players[pnum].connected == CONNECT_DISCONNECTED) || (pnum==Player_num))) { pnum = (pnum+1)%N_players; count++; } if (count == N_players) { //if can't valid non-player person, use the player pnum = Player_num; } segnum = pick_connected_segment(&Objects[Players[pnum].objnum], cur_drop_depth); if (segnum == -1) { cur_drop_depth--; continue; } if (Segments[segnum].special == SEGMENT_IS_CONTROLCEN) {segnum = -1;} else { //don't drop in any children of control centers int i; for (i=0;i<6;i++) { int ch = Segments[segnum].children[i]; if (IS_CHILD(ch) && Segments[ch].special == SEGMENT_IS_CONTROLCEN) { segnum = -1; break; } } } //bail if not far enough from original position if (segnum != -1) { compute_segment_center(&tempv, &Segments[segnum]); if (find_connected_distance(player_pos,player_seg,&tempv,segnum,-1,WID_FLY_FLAG) < i2f(20)*cur_drop_depth) { segnum = -1; } } cur_drop_depth--; } if (segnum == -1) { cur_drop_depth = BASE_NET_DROP_DEPTH; while (cur_drop_depth > 0 && segnum == -1) // before dropping in random segment, try to find ANY segment which is connected to the player responsible for the drop so object will not spawn in inaccessible areas { segnum = pick_connected_segment(&Objects[Players[Player_num].objnum], --cur_drop_depth); if (Segments[segnum].special == SEGMENT_IS_CONTROLCEN) segnum = -1; } return ((segnum == -1)?((d_rand() * Highest_segment_index) >> 15):segnum); // basically it should be impossible segnum == -1 now... but oh well... } else return segnum; } extern char PowerupsInMine[],MaxPowerupsAllowed[]; // ------------------------------------------------------------------------------------------------------ // Drop cloak powerup if in a network game. void maybe_drop_net_powerup(int powerup_type) { if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { int segnum, objnum; vms_vector new_pos; if (Game_mode & GM_NETWORK) { if (PowerupsInMine[powerup_type]>=MaxPowerupsAllowed[powerup_type]) return; } if (Control_center_destroyed || Endlevel_sequence) return; segnum = choose_drop_segment(); //--old-- segnum = (d_rand() * Highest_segment_index) >> 15; //--old-- Assert((segnum >= 0) && (segnum <= Highest_segment_index)); //--old-- if (segnum < 0) //--old-- segnum = -segnum; //--old-- while (segnum > Highest_segment_index) //--old-- segnum /= 2; Net_create_loc = 0; objnum = call_object_create_egg(&Objects[Players[Player_num].objnum], 1, OBJ_POWERUP, powerup_type); if (objnum < 0) return; #ifndef SHAREWARE pick_random_point_in_seg(&new_pos, segnum); #else compute_segment_center(&new_pos, &Segments[segnum]); #endif multi_send_create_powerup(powerup_type, segnum, objnum, &new_pos); Objects[objnum].pos = new_pos; vm_vec_zero(&Objects[objnum].mtype.phys_info.velocity); obj_relink(objnum, segnum); object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE ); } } // ------------------------------------------------------------------------------------------------------ // Return true if current segment contains some object. int segment_contains_object(int obj_type, int obj_id, int segnum) { int objnum; if (segnum == -1) return 0; objnum = Segments[segnum].objects; while (objnum != -1) if ((Objects[objnum].type == obj_type) && (Objects[objnum].id == obj_id)) return 1; else objnum = Objects[objnum].next; return 0; } // ------------------------------------------------------------------------------------------------------ int object_nearby_aux(int segnum, int object_type, int object_id, int depth) { int i; if (depth == 0) return 0; if (segment_contains_object(object_type, object_id, segnum)) return 1; for (i=0; isegnum, OBJ_POWERUP, weapon_id, 3); } // ------------------------------------------------------------------------------------------------------ void maybe_replace_powerup_with_energy(object *del_obj) { int weapon_index=-1; if (del_obj->contains_type != OBJ_POWERUP) return; if (del_obj->contains_id == POW_CLOAK) { if (weapon_nearby(del_obj, del_obj->contains_id)) { del_obj->contains_count = 0; } return; } switch (del_obj->contains_id) { case POW_VULCAN_WEAPON: weapon_index = VULCAN_INDEX; break; case POW_SPREADFIRE_WEAPON: weapon_index = SPREADFIRE_INDEX; break; #ifndef SHAREWARE case POW_PLASMA_WEAPON: weapon_index = PLASMA_INDEX; break; case POW_FUSION_WEAPON: weapon_index = FUSION_INDEX; break; #endif } // Don't drop vulcan ammo if player maxed out. if (((weapon_index == VULCAN_INDEX) || (del_obj->contains_id == POW_VULCAN_AMMO)) && (Players[Player_num].primary_ammo[VULCAN_INDEX] >= VULCAN_AMMO_MAX)) del_obj->contains_count = 0; else if (weapon_index != -1) { if ((player_has_weapon(weapon_index, 0) & HAS_WEAPON_FLAG) || weapon_nearby(del_obj, del_obj->contains_id)) { if (d_rand() > 16384) { del_obj->contains_count = 1; del_obj->contains_type = OBJ_POWERUP; if (weapon_index == VULCAN_INDEX) { del_obj->contains_id = POW_VULCAN_AMMO; } else { del_obj->contains_id = POW_ENERGY; } } else del_obj->contains_count = 0; } } else if (del_obj->contains_id == POW_QUAD_FIRE) if ((Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) || weapon_nearby(del_obj, del_obj->contains_id)) { if (d_rand() > 16384) { del_obj->contains_count = 1; del_obj->contains_type = OBJ_POWERUP; del_obj->contains_id = POW_ENERGY; } else del_obj->contains_count = 0; } // If this robot was gated in by the boss and it now contains energy, make it contain nothing, // else the room gets full of energy. if ( (del_obj->matcen_creator == BOSS_GATE_MATCEN_NUM) && (del_obj->contains_id == POW_ENERGY) && (del_obj->contains_type == OBJ_POWERUP) ) { del_obj->contains_count = 0; } // Change multiplayer extra-lives into invulnerability if ((Game_mode & GM_MULTI) && (del_obj->contains_id == POW_EXTRA_LIFE)) { del_obj->contains_id = POW_INVULNERABILITY; } } int drop_powerup(int type, int id, int num, vms_vector *init_vel, vms_vector *pos, int segnum) { int objnum=0, count; object *obj; vms_vector new_velocity, new_pos; fix old_mag; switch (type) { case OBJ_POWERUP: for (count=0; count= POW_KEY_BLUE) && (id <= POW_KEY_GOLD)) vm_vec_zero(&new_velocity); new_pos = *pos; // new_pos.x += (d_rand()-16384)*8; // new_pos.y += (d_rand()-16384)*8; // new_pos.z += (d_rand()-16384)*8; #ifdef NETWORK if (Game_mode & GM_MULTI) { if (Net_create_loc >= MAX_NET_CREATE_OBJECTS) { return (-1); } } #endif objnum = obj_create( type, id, segnum, &new_pos, &vmd_identity_matrix, Powerup_info[id].size, CT_POWERUP, MT_PHYSICS, RT_POWERUP); if (objnum < 0 ) { Int3(); return objnum; } #ifdef NETWORK if (Game_mode & GM_MULTI) { Net_create_objnums[Net_create_loc++] = objnum; } #endif obj = &Objects[objnum]; obj->mtype.phys_info.velocity = new_velocity; obj->mtype.phys_info.drag = 512; //1024; obj->mtype.phys_info.mass = F1_0; obj->mtype.phys_info.flags = PF_BOUNCE; obj->rtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num; obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time; obj->rtype.vclip_info.framenum = 0; switch (obj->id) { case POW_MISSILE_1: case POW_MISSILE_4: case POW_SHIELD_BOOST: case POW_ENERGY: obj->lifeleft = (d_rand() + F1_0*3) * 64; // Lives for 3 to 3.5 binary minutes (a binary minute is 64 seconds) if (Game_mode & GM_MULTI) obj->lifeleft /= 2; break; default: // if (Game_mode & GM_MULTI) // obj->lifeleft = (d_rand() + F1_0*3) * 64; // Lives for 5 to 5.5 binary minutes (a binary minute is 64 seconds) break; } } break; case OBJ_ROBOT: for (count=0; countrtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; //set Physics info obj->mtype.phys_info.velocity = new_velocity; obj->mtype.phys_info.mass = Robot_info[obj->id].mass; obj->mtype.phys_info.drag = Robot_info[obj->id].drag; obj->mtype.phys_info.flags |= (PF_LEVELLING); obj->shields = Robot_info[obj->id].strength; obj->ctype.ai_info.behavior = AIB_NORMAL; Ai_local_info[obj-Objects].player_awareness_type = PA_WEAPON_ROBOT_COLLISION; Ai_local_info[obj-Objects].player_awareness_time = F1_0*3; obj->ctype.ai_info.CURRENT_STATE = AIS_LOCK; obj->ctype.ai_info.GOAL_STATE = AIS_LOCK; obj->ctype.ai_info.REMOTE_OWNER = -1; } break; default: Error("Error: Illegal type (%i) in object spawning.\n", type); } return objnum; } // ---------------------------------------------------------------------------- // Returns created object number. // If object dropped by player, set flag. int object_create_egg(object *objp) { int rval; rval = drop_powerup(objp->contains_type, objp->contains_id, objp->contains_count, &objp->mtype.phys_info.velocity, &objp->pos, objp->segnum); return rval; } #if 0 // implemented differently // get maximum number of objects of this type,id that may be created // returns -1 if no maximum // uses initial number of objects (level + players) int egg_max_count(int type, int id) { int i, current; if (type == OBJ_POWERUP && multi_allow_powerup_mask[id]) { // only check 'important' powerups (no shield,energy,conc) current = 0; for (i = 0; i < Highest_object_count; i++) { if ((Objects[i].type == OBJ_POWERUP && Objects[i].id == id) || (Objects[i].type == OBJ_ROBOT && Objects[i].contains_count > 0 && Objects[i].contains_type == OBJ_POWERUP && Objects[i].contains_id == id)) { current++; } } Assert(current <= Powerup_initial[id]); return Powerup_initial[id] - current; } return -1; } #endif // ------------------------------------------------------------------------------------------------------- // Put count objects of type type (eg, powerup), id = id (eg, energy) into *objp, then drop them! Yippee! // Returns created object number. int call_object_create_egg(object *objp, int count, int type, int id) { if (count > 0) { objp->contains_count = count; objp->contains_type = type; objp->contains_id = id; return object_create_egg(objp); } return -1; } //what vclip does this explode with? int get_explosion_vclip(object *obj,int stage) { if (obj->type==OBJ_ROBOT) { if (stage==0 && Robot_info[obj->id].exp1_vclip_num>-1) return Robot_info[obj->id].exp1_vclip_num; else if (stage==1 && Robot_info[obj->id].exp2_vclip_num>-1) return Robot_info[obj->id].exp2_vclip_num; } else if (obj->type==OBJ_PLAYER && Player_ship->expl_vclip_num>-1) return Player_ship->expl_vclip_num; return VCLIP_SMALL_EXPLOSION; //default } //blow up a polygon model void explode_model(object *obj) { Assert(obj->render_type == RT_POLYOBJ); if (Dying_modelnums[obj->rtype.pobj_info.model_num] != -1) obj->rtype.pobj_info.model_num = Dying_modelnums[obj->rtype.pobj_info.model_num]; if (Polygon_models[obj->rtype.pobj_info.model_num].n_models > 1) { int i; for (i=1;irtype.pobj_info.model_num].n_models;i++) object_create_debris(obj,i); //make parent object only draw center part obj->rtype.pobj_info.subobj_flags=1; } } //if the object has a destroyed model, switch to it. Otherwise, delete it. void maybe_delete_object(object *del_obj) { if (Dead_modelnums[del_obj->rtype.pobj_info.model_num] != -1) { del_obj->rtype.pobj_info.model_num = Dead_modelnums[del_obj->rtype.pobj_info.model_num]; del_obj->flags |= OF_DESTROYED; } else { //normal, multi-stage explosion if (del_obj->type == OBJ_PLAYER) del_obj->render_type = RT_NONE; else del_obj->flags |= OF_SHOULD_BE_DEAD; } } // ------------------------------------------------------------------------------------------------------- //blow up an object. Takes the object to destroy, and the point of impact void explode_object(object *hitobj,fix delay_time) { if (hitobj->flags & OF_EXPLODING) return; if (delay_time) { //wait a little while before creating explosion int objnum; object *obj; //create a placeholder object to do the delay, with id==-1 objnum = obj_create( OBJ_FIREBALL,-1,hitobj->segnum,&hitobj->pos,&vmd_identity_matrix,0, CT_EXPLOSION,MT_NONE,RT_NONE); if (objnum < 0 ) { maybe_delete_object(hitobj); //no explosion, die instantly Int3(); return; } obj = &Objects[objnum]; //now set explosion-specific data obj->lifeleft = delay_time; obj->ctype.expl_info.delete_objnum = hitobj-Objects; #ifndef NDEBUG if (obj->ctype.expl_info.delete_objnum < 0) Int3(); // See Rob! #endif obj->ctype.expl_info.delete_time = -1; obj->ctype.expl_info.spawn_time = 0; } else { object *expl_obj; int vclip_num; vclip_num = get_explosion_vclip(hitobj,0); expl_obj = object_create_explosion(hitobj->segnum, &hitobj->pos, fixmul(hitobj->size,EXPLOSION_SCALE), vclip_num ); if (! expl_obj) { maybe_delete_object(hitobj); //no explosion, die instantly return; } //don't make debris explosions have physics, because they often //happen when the debris has hit the wall, so the fireball is trying //to move into the wall, which shows off FVI problems. if (hitobj->type!=OBJ_DEBRIS && hitobj->movement_type==MT_PHYSICS) { expl_obj->movement_type = MT_PHYSICS; expl_obj->mtype.phys_info = hitobj->mtype.phys_info; } if (hitobj->render_type==RT_POLYOBJ && hitobj->type!=OBJ_DEBRIS) explode_model(hitobj); maybe_delete_object(hitobj); } hitobj->flags |= OF_EXPLODING; //say that this is blowing up hitobj->control_type = CT_NONE; //become inert while exploding } //do whatever needs to be done for this piece of debris for this frame void do_debris_frame(object *obj) { Assert(obj->control_type == CT_DEBRIS); if (obj->lifeleft < 0) explode_object(obj,0); } //do whatever needs to be done for this explosion for this frame void do_explosion_sequence(object *obj) { Assert(obj->control_type == CT_EXPLOSION); //See if we should die of old age if (obj->lifeleft <= 0 ) { // We died of old age obj->flags |= OF_SHOULD_BE_DEAD; obj->lifeleft = 0; } //See if we should create a secondary explosion if (obj->lifeleft <= obj->ctype.expl_info.spawn_time) { object *expl_obj,*del_obj; int vclip_num; vms_vector *spawn_pos; if ((obj->ctype.expl_info.delete_objnum < 0) || (obj->ctype.expl_info.delete_objnum > Highest_object_index)) { Int3(); // get Rob, please... thanks return; } del_obj = &Objects[obj->ctype.expl_info.delete_objnum]; spawn_pos = &del_obj->pos; Assert(del_obj->type==OBJ_ROBOT || del_obj->type==OBJ_CLUTTER || del_obj->type==OBJ_CNTRLCEN || del_obj->type == OBJ_PLAYER); Assert(del_obj->segnum != -1); vclip_num = get_explosion_vclip(del_obj,1); expl_obj = object_create_explosion( del_obj->segnum, spawn_pos, fixmul(del_obj->size, EXPLOSION_SCALE), vclip_num ); if ((del_obj->contains_count > 0) && !(Game_mode & GM_MULTI)) { // Multiplayer handled outside of this code!! // If dropping a weapon that the player has, drop energy instead, unless it's vulcan, in which case drop vulcan ammo. if (del_obj->contains_type == OBJ_POWERUP) maybe_replace_powerup_with_energy(del_obj); object_create_egg(del_obj); } else if ((del_obj->type == OBJ_ROBOT) && !(Game_mode & GM_MULTI)) { // Multiplayer handled outside this code!! robot_info *robptr = &Robot_info[del_obj->id]; if (robptr->contains_count) { if (((d_rand() * 16) >> 15) < robptr->contains_prob) { del_obj->contains_count = ((d_rand() * robptr->contains_count) >> 15) + 1; del_obj->contains_type = robptr->contains_type; del_obj->contains_id = robptr->contains_id; maybe_replace_powerup_with_energy(del_obj); object_create_egg(del_obj); } } } if ( Robot_info[del_obj->id].exp2_sound_num > -1 ) digi_link_sound_to_pos( Robot_info[del_obj->id].exp2_sound_num, del_obj->segnum, 0, spawn_pos, 0, F1_0 ); //PLAY_SOUND_3D( Robot_info[del_obj->id].exp2_sound_num, spawn_pos, del_obj->segnum ); obj->ctype.expl_info.spawn_time = -1; //make debris if (del_obj->render_type==RT_POLYOBJ) explode_model(del_obj); //explode a polygon model //set some parm in explosion //If num_objects < MAX_USED_OBJECTS, expl_obj could be set to dead before this setting causing the delete_obj not to be removed. If so, directly delete del_obj if (expl_obj && !(expl_obj->flags & OF_SHOULD_BE_DEAD)) { if (del_obj->movement_type == MT_PHYSICS) { expl_obj->movement_type = MT_PHYSICS; expl_obj->mtype.phys_info = del_obj->mtype.phys_info; } expl_obj->ctype.expl_info.delete_time = expl_obj->lifeleft/2; expl_obj->ctype.expl_info.delete_objnum = del_obj-Objects; #ifndef NDEBUG if (obj->ctype.expl_info.delete_objnum < 0) Int3(); // See Rob! #endif } else { maybe_delete_object(del_obj); } } //See if we should delete an object if (obj->lifeleft <= obj->ctype.expl_info.delete_time) { object *del_obj = &Objects[obj->ctype.expl_info.delete_objnum]; obj->ctype.expl_info.delete_time = -1; maybe_delete_object(del_obj); } } typedef struct expl_wall { int segnum,sidenum; fix time; } expl_wall; #define MAX_EXPLODING_WALLS 10 #define EXPL_WALL_TIME (f1_0) #define EXPL_WALL_TOTAL_FIREBALLS 32 #define EXPL_WALL_FIREBALL_SIZE 0x48000 //smallest size expl_wall expl_wall_list[MAX_EXPLODING_WALLS]; //--unused-- int n_exploding_walls; void init_exploding_walls() { int i; for (i=0;i EXPL_WALL_TIME) expl_wall_list[i].time = EXPL_WALL_TIME; if (expl_wall_list[i].time>(EXPL_WALL_TIME*3)/4) { segment *seg,*csegp; int cside,a,n; seg = &Segments[segnum]; a = Walls[seg->sides[sidenum].wall_num].clip_num; n = WallAnims[a].num_frames; csegp = &Segments[seg->children[sidenum]]; cside = find_connect_side(seg, csegp); wall_set_tmap_num(seg,sidenum,csegp,cside,a,n-1); Walls[seg->sides[sidenum].wall_num].flags |= WALL_BLASTED; Walls[csegp->sides[cside].wall_num].flags |= WALL_BLASTED; } newfrac = fixdiv(expl_wall_list[i].time,EXPL_WALL_TIME); old_count = f2i(EXPL_WALL_TOTAL_FIREBALLS * fixmul(oldfrac,oldfrac)); new_count = f2i(EXPL_WALL_TOTAL_FIREBALLS * fixmul(newfrac,newfrac)); //n = new_count - old_count; //now create all the next explosions for (e=old_count;e= EXPL_WALL_TIME) expl_wall_list[i].segnum = -1; //flag this slot as free } } } dxx-rebirth-0.58.1-d1x/main/fireball.h000066400000000000000000000075711217717257200174410ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/fireball.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:41:27 $ * * Header for fireball.c * * $Log: fireball.h,v $ * Revision 1.1.1.1 2006/03/17 19:41:27 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:17 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:27:03 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.13 1995/01/17 12:14:38 john * Made walls, object explosion vclips load at level start. * * Revision 1.12 1995/01/13 15:41:52 rob * Added prototype for maybe_replace_powerup_with_energy * * Revision 1.11 1994/11/17 16:28:36 rob * Changed maybe_drop_cloak_powerup to maybe_drop_net_powerup (more * generic and useful) * * Revision 1.10 1994/10/12 08:03:42 mike * Prototype maybe_drop_cloak_powerup. * * Revision 1.9 1994/10/11 12:24:39 matt * Cleaned up/change badass explosion calls * * Revision 1.8 1994/09/07 16:00:34 mike * Add object pointer to parameter list of object_create_badass_explosion. * * Revision 1.7 1994/09/02 14:00:39 matt * Simplified explode_object() & mutliple-stage explosions * * Revision 1.6 1994/08/17 16:49:58 john * Added damaging fireballs, missiles. * * Revision 1.5 1994/07/14 22:39:19 matt * Added exploding doors * * Revision 1.4 1994/06/08 10:56:36 matt * Improved debris: now get submodel size from new POF files; debris now has * limited life; debris can now be blown up. * * Revision 1.3 1994/04/01 13:35:44 matt * Added multiple-stage explosions * * Revision 1.2 1994/02/17 11:33:32 matt * Changes in object system * * Revision 1.1 1994/02/16 22:41:15 matt * Initial revision * * */ #ifndef _FIREBALL_H #define _FIREBALL_H // explosion types #define ET_SPARKS 0 //little sparks, like when laser hits wall #define ET_MULTI_START 1 //first part of multi-part explosion #define ET_MULTI_SECOND 2 //second part of multi-part explosion object *object_create_explosion(short segnum, vms_vector *position, fix size, int vclip_type); object *object_create_muzzle_flash(short segnum, vms_vector *position, fix size, int vclip_type); object *object_create_badass_explosion(object *objp, short segnum, vms_vector *position, fix size, int vclip_type, fix maxdamage, fix maxdistance, fix maxforce, int parent); // blows up a badass weapon, creating the badass explosion // return the explosion object object *explode_badass_weapon(object *obj); // blows up the player with a badass explosion // return the explosion object object *explode_badass_player(object *obj); void explode_object(object *obj,fix delay_time); void do_explosion_sequence(object *obj); void do_debris_frame(object *obj); // deal with debris for this frame void draw_fireball(object *obj); void explode_wall(int segnum, int sidenum); void do_exploding_wall_frame(void); void init_exploding_walls(void); extern void maybe_drop_net_powerup(int powerup_type); extern void maybe_replace_powerup_with_energy(object *del_obj); extern int get_explosion_vclip(object *obj, int stage); #endif dxx-rebirth-0.58.1-d1x/main/fuelcen.c000066400000000000000000000477401217717257200172770ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for refueling centers. * */ #include #include #include #include #include "inferno.h" #include "fuelcen.h" #include "gameseg.h" #include "game.h" // For FrameTime #include "dxxerror.h" #include "gauges.h" #include "vclip.h" #include "fireball.h" #include "robot.h" #include "byteswap.h" #include "wall.h" #include "sounds.h" #include "morph.h" #include "3d.h" #include "bm.h" #include "polyobj.h" #include "ai.h" #include "gamemine.h" #include "gamesave.h" #include "player.h" #include "collide.h" #include "laser.h" #include "multi.h" #include "multibot.h" #include "gameseq.h" // The max number of fuel stations per mine. fix Fuelcen_refill_speed = i2f(1); fix Fuelcen_give_amount = i2f(25); fix Fuelcen_max_amount = i2f(100); // Every time a robot is created in the morphing code, it decreases capacity of the morpher // by this amount... when capacity gets to 0, no more morphers... fix EnergyToCreateOneRobot = i2f(1); #define MATCEN_HP_DEFAULT F1_0*500; // Hitpoints #define MATCEN_INTERVAL_DEFAULT F1_0*5; // 5 seconds matcen_info RobotCenters[MAX_ROBOT_CENTERS]; int Num_robot_centers; FuelCenter Station[MAX_NUM_FUELCENS]; int Num_fuelcenters = 0; segment * PlayerSegment= NULL; #ifdef EDITOR char Special_names[MAX_CENTER_TYPES][11] = { "NOTHING ", "FUELCEN ", "REPAIRCEN ", "CONTROLCEN", "ROBOTMAKER", }; #endif //------------------------------------------------------------ // Resets all fuel center info void fuelcen_reset() { int i; Num_fuelcenters = 0; for(i=0; ispecial; switch( station_type ) { case SEGMENT_IS_NOTHING: return; case SEGMENT_IS_FUELCEN: case SEGMENT_IS_REPAIRCEN: case SEGMENT_IS_CONTROLCEN: case SEGMENT_IS_ROBOTMAKER: break; default: Error( "Invalid station type %d in fuelcen.c\n", station_type ); } Assert( (segp != NULL) ); if ( segp == NULL ) return; Assert( Num_fuelcenters < MAX_NUM_FUELCENS ); Assert( Num_fuelcenters > -1 ); segp->value = Num_fuelcenters; Station[Num_fuelcenters].Type = station_type; Station[Num_fuelcenters].MaxCapacity = Fuelcen_max_amount; Station[Num_fuelcenters].Capacity = Station[Num_fuelcenters].MaxCapacity; Station[Num_fuelcenters].segnum = segp-Segments; Station[Num_fuelcenters].Timer = -1; Station[Num_fuelcenters].Flag = 0; // Station[Num_fuelcenters].NextRobotType = -1; // Station[Num_fuelcenters].last_created_obj=NULL; // Station[Num_fuelcenters].last_created_sig = -1; compute_segment_center(&Station[Num_fuelcenters].Center, segp); // if (station_type == SEGMENT_IS_ROBOTMAKER) // Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3); Num_fuelcenters++; } //------------------------------------------------------------ // Adds a matcen that already is a special type into the Station array. // This function is separate from other fuelcens because we don't want values reset. void matcen_create( segment *segp) { int station_type = segp->special; Assert( (segp != NULL) ); Assert(station_type == SEGMENT_IS_ROBOTMAKER); if ( segp == NULL ) return; Assert( Num_fuelcenters < MAX_NUM_FUELCENS ); Assert( Num_fuelcenters > -1 ); segp->value = Num_fuelcenters; Station[Num_fuelcenters].Type = station_type; Station[Num_fuelcenters].Capacity = i2f(Difficulty_level + 3); Station[Num_fuelcenters].MaxCapacity = Station[Num_fuelcenters].Capacity; Station[Num_fuelcenters].segnum = segp-Segments; Station[Num_fuelcenters].Timer = -1; Station[Num_fuelcenters].Flag = 0; // Station[Num_fuelcenters].NextRobotType = -1; // Station[Num_fuelcenters].last_created_obj=NULL; // Station[Num_fuelcenters].last_created_sig = -1; compute_segment_center(&Station[Num_fuelcenters].Center, segp ); segp->matcen_num = Num_robot_centers; Num_robot_centers++; RobotCenters[segp->matcen_num].hit_points = MATCEN_HP_DEFAULT; RobotCenters[segp->matcen_num].interval = MATCEN_INTERVAL_DEFAULT; RobotCenters[segp->matcen_num].segnum = segp-Segments; RobotCenters[segp->matcen_num].fuelcen_num = Num_fuelcenters; Num_fuelcenters++; } //------------------------------------------------------------ // Adds a segment that already is a special type into the Station array. void fuelcen_activate( segment * segp, int station_type ) { segp->special = station_type; if (segp->special == SEGMENT_IS_ROBOTMAKER) matcen_create( segp); else fuelcen_create( segp); } // The lower this number is, the more quickly the center can be re-triggered. // If it's too low, it can mean all the robots won't be put out, but for about 5 // robots, that's not real likely. #define MATCEN_LIFE (i2f(30-2*Difficulty_level)) //------------------------------------------------------------ // Trigger (enable) the materialization center in segment segnum void trigger_matcen(int segnum) { segment *segp = &Segments[segnum]; vms_vector pos, delta; FuelCenter *robotcen; int objnum; Assert(segp->special == SEGMENT_IS_ROBOTMAKER); Assert(segp->matcen_num < Num_fuelcenters); Assert((segp->matcen_num >= 0) && (segp->matcen_num <= Highest_segment_index)); robotcen = &Station[RobotCenters[segp->matcen_num].fuelcen_num]; if (robotcen->Enabled == 1) return; if (!robotcen->Lives) return; robotcen->Lives--; robotcen->Timer = F1_0*1000; // Make sure the first robot gets emitted right away. robotcen->Enabled = 1; // Say this center is enabled, it can create robots. robotcen->Capacity = i2f(Difficulty_level + 3); robotcen->Disable_time = MATCEN_LIFE; // Create a bright object in the segment. pos = robotcen->Center; vm_vec_sub(&delta, &Vertices[Segments[segnum].verts[0]], &robotcen->Center); vm_vec_scale_add2(&pos, &delta, F1_0/2); objnum = obj_create( OBJ_LIGHT, 0, segnum, &pos, NULL, 0, CT_LIGHT, MT_NONE, RT_NONE ); if (objnum != -1) { Objects[objnum].lifeleft = MATCEN_LIFE; Objects[objnum].ctype.light_info.intensity = i2f(8); // Light cast by a fuelcen. } else { Int3(); } } #ifdef EDITOR //------------------------------------------------------------ // Takes away a segment's fuel center properties. // Deletes the segment point entry in the FuelCenter list. void fuelcen_delete( segment * segp ) { int i, j; Restart: ; for (i=0; imatcen_num; j segp->matcen_num ) Segments[Station[j].segnum].matcen_num--; } } Num_fuelcenters--; for (j=i; jspecial = 0; goto Restart; } } } #endif #define ROBOT_GEN_TIME (i2f(5)) object * create_morph_robot( segment *segp, vms_vector *object_pos, int object_id) { short objnum; object *obj; int default_behavior; Players[Player_num].num_robots_level++; Players[Player_num].num_robots_total++; objnum = obj_create(OBJ_ROBOT, object_id, segp-Segments, object_pos, &vmd_identity_matrix, Polygon_models[Robot_info[object_id].model_num].rad, CT_AI, MT_PHYSICS, RT_POLYOBJ); if ( objnum < 0 ) { Int3(); return NULL; } obj = &Objects[objnum]; //Set polygon-object-specific data obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; //set Physics info obj->mtype.phys_info.mass = Robot_info[obj->id].mass; obj->mtype.phys_info.drag = Robot_info[obj->id].drag; obj->mtype.phys_info.flags |= (PF_LEVELLING); obj->shields = Robot_info[obj->id].strength; default_behavior = AIB_NORMAL; if (object_id == 10) // This is a toaster guy! default_behavior = AIB_RUN_FROM; init_ai_object(obj-Objects, default_behavior, -1 ); // Note, -1 = segment this robot goes to to hide, should probably be something useful create_n_segment_path(obj, 6, -1); // Create a 6 segment path from creation point. if (default_behavior == AIB_RUN_FROM) Ai_local_info[objnum].mode = AIM_RUN_FROM_OBJECT; return obj; } int Num_extry_robots = 15; // ---------------------------------------------------------------------------------------------------------- void robotmaker_proc( FuelCenter * robotcen ) { fix dist_to_player; vms_vector cur_object_loc; //, direction; int matcen_num, segnum, objnum; object *obj; fix top_time; vms_vector direction; if (robotcen->Enabled == 0) return; if (robotcen->Disable_time > 0) { robotcen->Disable_time -= FrameTime; if (robotcen->Disable_time <= 0) { robotcen->Enabled = 0; } } // No robot making in multiplayer mode. #ifdef NETWORK #ifndef SHAREWARE if ((Game_mode & GM_MULTI) && (!(Game_mode & GM_MULTI_ROBOTS) || !multi_i_am_master())) return; #else if (Game_mode & GM_MULTI) return; #endif #endif // Wait until transmorgafier has capacity to make a robot... if ( robotcen->Capacity <= 0 ) { return; } matcen_num = Segments[robotcen->segnum].matcen_num; if ( matcen_num == -1 ) { return; } if (RobotCenters[matcen_num].robot_flags[0] == 0) { return; } // Wait until we have a free slot for this puppy... // <<<<<<<<<<<<<<<< Num robots in mine >>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<< Max robots in mine >>>>>>>>>>>>>>> if ( (Players[Player_num].num_robots_level - Players[Player_num].num_kills_level) >= (Gamesave_num_org_robots + Num_extry_robots ) ) { return; } robotcen->Timer += FrameTime; switch( robotcen->Flag ) { case 0: // Wait until next robot can generate if (Game_mode & GM_MULTI) { top_time = ROBOT_GEN_TIME; } else { dist_to_player = vm_vec_dist_quick( &ConsoleObject->pos, &robotcen->Center ); top_time = dist_to_player/64 + d_rand() * 2 + F1_0*2; if ( top_time > ROBOT_GEN_TIME ) top_time = ROBOT_GEN_TIME + d_rand(); if ( top_time < F1_0*2 ) top_time = F1_0*3/2 + d_rand()*2; } if (robotcen->Timer > top_time ) { int count=0; int i, my_station_num = robotcen-Station; object *obj; // Make sure this robotmaker hasn't put out its max without having any of them killed. for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_ROBOT) if ((Objects[i].matcen_creator^0x80) == my_station_num) count++; if (count > Difficulty_level + 3) { robotcen->Timer /= 2; return; } // Whack on any robot or player in the matcen segment. count=0; segnum = robotcen->segnum; for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) { count++; if ( count > MAX_OBJECTS ) { Int3(); return; } if (Objects[objnum].type==OBJ_ROBOT) { collide_robot_and_materialization_center(&Objects[objnum]); robotcen->Timer = top_time/2; return; } else if (Objects[objnum].type==OBJ_PLAYER ) { collide_player_and_materialization_center(&Objects[objnum]); robotcen->Timer = top_time/2; return; } } compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]); // HACK!!! The 10 under here should be something equal to the 1/2 the size of the segment. obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT ); if (obj) extract_orient_from_segment(&obj->orient,&Segments[robotcen->segnum]); if ( Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1 ) { digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 ); } robotcen->Flag = 1; robotcen->Timer = 0; } break; case 1: // Wait until 1/2 second after VCLIP started. if (robotcen->Timer > (Vclip[VCLIP_MORPHING_ROBOT].play_time/2) ) { robotcen->Capacity -= EnergyToCreateOneRobot; robotcen->Flag = 0; robotcen->Timer = 0; compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]); // If this is the first materialization, set to valid robot. if (RobotCenters[matcen_num].robot_flags[0] != 0) { int type; uint flags; sbyte legal_types[32]; // 32 bits in a word, the width of robot_flags. int num_types, robot_index; robot_index = 0; num_types = 0; flags = RobotCenters[matcen_num].robot_flags[0]; while (flags) { if (flags & 1) legal_types[num_types++] = robot_index; flags >>= 1; robot_index++; } if (num_types == 1) type = legal_types[0]; else type = legal_types[(d_rand() * num_types) / 32768]; obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type ); if (obj != NULL) { #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_create_robot(robotcen-Station, obj-Objects, type); #endif #endif obj->matcen_creator = (robotcen-Station) | 0x80; // Make object faces player... vm_vec_sub( &direction, &ConsoleObject->pos,&obj->pos ); vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL); morph_start( obj ); //robotcen->last_created_obj = obj; //robotcen->last_created_sig = robotcen->last_created_obj->signature; } } } break; default: robotcen->Flag = 0; robotcen->Timer = 0; } } #ifndef M_PI #define M_PI 3.14159 #endif //------------------------------------------------------------- // Called once per frame, replenishes fuel supply. void fuelcen_update_all() { int i; fix AmountToreplenish; AmountToreplenish = fixmul(FrameTime,Fuelcen_refill_speed); for (i=0; i 0) && (PlayerSegment!=&Segments[Station[i].segnum]) ) { if ( Station[i].Capacity < Station[i].MaxCapacity ) { Station[i].Capacity += AmountToreplenish; if ( Station[i].Capacity >= Station[i].MaxCapacity ) { Station[i].Capacity = Station[i].MaxCapacity; //gauge_message( "Fuel center is fully recharged! " ); } } } } } //------------------------------------------------------------- fix fuelcen_give_fuel(segment *segp, fix MaxAmountCanTake ) { static fix64 last_play_time = 0; #define REFUEL_SOUND_DELAY (F1_0/3) Assert( segp != NULL ); PlayerSegment = segp; if ( (segp) && (segp->special==SEGMENT_IS_FUELCEN) ) { fix amount; // if (Station[segp->value].MaxCapacity<=0) { // HUD_init_message(HM_DEFAULT, "Fuelcenter %d is destroyed.", segp->value ); // return 0; // } // if (Station[segp->value].Capacity<=0) { // HUD_init_message(HM_DEFAULT, "Fuelcenter %d is empty.", segp->value ); // return 0; // } if (MaxAmountCanTake <= 0 ) { // //gauge_message( "Fueled up!"); return 0; } amount = fixmul(FrameTime,Fuelcen_give_amount); if (amount > MaxAmountCanTake ) amount = MaxAmountCanTake; // if (!(Game_mode & GM_MULTI)) // if ( Station[segp->value].Capacity < amount ) { // amount = Station[segp->value].Capacity; // Station[segp->value].Capacity = 0; // } else { // Station[segp->value].Capacity -= amount; // } if (last_play_time + REFUEL_SOUND_DELAY < GameTime64 || last_play_time > GameTime64) { last_play_time = GameTime64; digi_play_sample( SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2 ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_REFUEL_STATION_GIVING_FUEL, F1_0/2); #endif } //HUD_init_message(HM_DEFAULT, "Fuelcen %d has %d/%d fuel", segp->value,f2i(Station[segp->value].Capacity),f2i(Station[segp->value].MaxCapacity) ); return amount; } else { return 0; } } // -------------------------------------------------------------------------------------------- void disable_matcens(void) { int i; for (i=0; irobot_flags[0] = PHYSFSX_readInt(fp); if (version > 25) /*mi->robot_flags2 =*/ PHYSFSX_readInt(fp); mi->hit_points = PHYSFSX_readFix(fp); mi->interval = PHYSFSX_readFix(fp); mi->segnum = PHYSFSX_readShort(fp); mi->fuelcen_num = PHYSFSX_readShort(fp); } void matcen_info_swap(matcen_info *mi, int swap) { if (!swap) return; mi->robot_flags[0] = SWAPINT(mi->robot_flags[0]); //if (version > 25) /*mi->robot_flags2 = SWAPINT(mi->robot_flags2);*/ mi->hit_points = SWAPINT(mi->hit_points); mi->interval = SWAPINT(mi->interval); mi->segnum = SWAPSHORT(mi->segnum); mi->fuelcen_num = SWAPSHORT(mi->fuelcen_num); } /* * reads n matcen_info structs from a PHYSFS_file and swaps if specified */ void matcen_info_read_n_swap(matcen_info *mi, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, mi, sizeof(matcen_info), n); if (swap) for (i = 0; i < n; i++) matcen_info_swap(&mi[i], swap); } void matcen_info_write(matcen_info *mi, short version, PHYSFS_file *fp) { PHYSFS_writeSLE32(fp, mi->robot_flags[0]); if (version >= 27) PHYSFS_writeSLE32(fp, 0 /*mi->robot_flags[1]*/); PHYSFSX_writeFix(fp, mi->hit_points); PHYSFSX_writeFix(fp, mi->interval); PHYSFS_writeSLE16(fp, mi->segnum); PHYSFS_writeSLE16(fp, mi->fuelcen_num); } void fuelcen_swap(FuelCenter *fc, int swap) { if (!swap) return; fc->Type = SWAPINT(fc->Type); fc->segnum = SWAPINT(fc->segnum); fc->Capacity = SWAPINT(fc->Capacity); fc->MaxCapacity = SWAPINT(fc->MaxCapacity); fc->Timer = SWAPINT(fc->Timer); fc->Disable_time = SWAPINT(fc->Disable_time); fc->Center.x = SWAPINT(fc->Center.x); fc->Center.y = SWAPINT(fc->Center.y); fc->Center.z = SWAPINT(fc->Center.z); } /* * reads n FuelCenter structs from a PHYSFS_file and swaps if specified */ void fuelcen_read_n_swap(FuelCenter *fc, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, fc, sizeof(FuelCenter), n); if (swap) for (i = 0; i < n; i++) fuelcen_swap(&fc[i], swap); } dxx-rebirth-0.58.1-d1x/main/fuelcen.h000066400000000000000000000126741217717257200173020ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Definitions for fueling centers. * */ #ifndef _FUELCEN_H #define _FUELCEN_H #include "segment.h" #include "object.h" #include "switch.h" //------------------------------------------------------------ // A refueling center is one segment... to identify it in the // segment structure, the "special" field is set to // SEGMENT_IS_FUELCEN. The "value" field is then used for how // much fuel the center has left, with a maximum value of 100. //------------------------------------------------------------- // To hook into Inferno: // * When all segents are deleted or before a new mine is created // or loaded, call fuelcen_reset(). // * Add call to fuelcen_create(segment * segp) to make a segment // which isn't a fuel center be a fuel center. // * When a mine is loaded call fuelcen_activate(segp) with each // new segment as it loads. Always do this. // * When a segment is deleted, always call fuelcen_delete(segp). // * Call fuelcen_replentish_all() to fill 'em all up, like when // a new game is started. // * When an object that needs to be refueled is in a segment, call // fuelcen_give_fuel(segp) to get fuel. (Call once for any refueling // object once per frame with the object's current segment.) This // will return a value between 0 and 100 that tells how much fuel // he got. // Destroys all fuel centers, clears segment backpointer array. void fuelcen_reset(); // Create materialization center int create_matcen( segment * segp ); // Makes a segment a fuel center. void fuelcen_create( segment * segp); // Makes a fuel center active... needs to be called when // a segment is loaded from disk. void fuelcen_activate( segment * segp, int station_type ); // Deletes a segment as a fuel center. void fuelcen_delete( segment * segp ); // Charges all fuel centers to max capacity. void fuelcen_replentish_all(); // Create a matcen robot extern object *create_morph_robot(segment *segp, vms_vector *object_pos, int object_id); // Returns the amount of fuel this segment can give up. // Can be from 0 to 100. fix fuelcen_give_fuel(segment *segp, fix MaxAmountCanTake ); // Call once per frame. void fuelcen_update_all(); // Called when hit by laser. void fuelcen_damage(segment *segp, fix AmountOfDamage ); // Called to repair an object //--repair-- int refuel_do_repair_effect( object * obj, int first_time, int repair_seg ); #define MAX_NUM_FUELCENS 50 extern char Special_names[MAX_CENTER_TYPES][11]; //--repair-- //do the repair center for this frame //--repair-- void do_repair_sequence(object *obj); //--repair-- //--repair-- //see if we should start the repair center //--repair-- void check_start_repair_center(object *obj); //--repair-- //--repair-- //if repairing, cut it short //--repair-- abort_repair_center(); // An array of pointers to segments with fuel centers. typedef struct FuelCenter { int Type; int segnum; sbyte Flag; sbyte Enabled; sbyte Lives; // Number of times this can be enabled. sbyte dum1; fix Capacity; fix MaxCapacity; fix Timer; // used in matcen for when next robot comes out fix Disable_time; // Time until center disabled. //object *last_created_obj; //int last_created_sig; vms_vector Center; } __pack__ FuelCenter; // The max number of robot centers per mine. #define MAX_ROBOT_CENTERS 20 extern int Num_robot_centers; typedef struct matcen_info { int robot_flags[1]; // Up to 32 different robots fix hit_points; // How hard it is to destroy this particular matcen fix interval; // Interval between materialogrifizations short segnum; // Segment this is attached to. short fuelcen_num; // Index in fuelcen array. } __pack__ matcen_info; extern matcen_info RobotCenters[MAX_ROBOT_CENTERS]; extern int Fuelcen_control_center_dead_modelnum; extern fix Fuelcen_control_center_strength; //--repair-- extern object *RepairObj; // which object getting repaired, or NULL // Called when a materialization center gets triggered by the player // flying through some trigger! extern void trigger_matcen(int segnum); extern void disable_matcens(void); extern FuelCenter Station[MAX_NUM_FUELCENS]; extern int Num_fuelcenters; extern void init_all_matcens(void); extern fix EnergyToCreateOneRobot; /* * reads a matcen_info structure from a PHYSFS_file */ void matcen_info_read(matcen_info *ps, PHYSFS_file *fp, int version); /* * reads n matcen_info structs from a PHYSFS_file and swaps if specified */ void matcen_info_read_n_swap(matcen_info *mi, int n, int swap, PHYSFS_file *fp); void matcen_info_write(matcen_info *mi, short version, PHYSFS_file *fp); /* * reads n FuelCenter structs from a PHYSFS_file and swaps if specified */ void fuelcen_read_n_swap(FuelCenter *fc, int n, int swap, PHYSFS_file *fp); #endif dxx-rebirth-0.58.1-d1x/main/fvi.c000066400000000000000000001115531217717257200164340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * New home for find_vector_intersection() * */ #include #include #include "dxxerror.h" #include "inferno.h" #include "fvi.h" #include "segment.h" #include "object.h" #include "wall.h" #include "laser.h" #include "rle.h" #include "robot.h" #include "piggy.h" #include "player.h" #include "fix.h" #define face_type_num(nfaces,face_num,tri_edge) ((nfaces==1)?0:(tri_edge*2 + face_num)) //find the point on the specified plane where the line intersects //returns true if point found, false if line parallel to plane //new_pnt is the found point on the plane //plane_pnt & plane_norm describe the plane //p0 & p1 are the ends of the line static int find_plane_line_intersection(vms_vector *new_pnt,vms_vector *plane_pnt,vms_vector *plane_norm,const vms_vector *p0,const vms_vector *p1,fix rad) { vms_vector d,w; fix num,den; vm_vec_sub(&d,p1,p0); vm_vec_sub(&w,p0,plane_pnt); num = vm_vec_dot(plane_norm,&w); den = -vm_vec_dot(plane_norm,&d); num -= rad; //move point out by rad if (den == 0) // moving parallel to wall, so can't hit it return 0; //check for various bad values if (den > 0 && (-num>>15) >= den) //will overflow (large negative) num = (f1_0-f0_5)*den; if (den > 0 && num > den) //frac greater than one return 0; if (den < 0 && num < den) //frac greater than one return 0; if (labs (num) / (f1_0 / 2) >= labs (den)) return 0; vm_vec_scale2(&d,num,den); vm_vec_add(new_pnt,p0,&d); return 1; } typedef struct vec2d { fix i,j; } vec2d; //given largest componant of normal, return i & j //if largest componant is negative, swap i & j int ij_table[3][2] = { {2,1}, //pos x biggest {0,2}, //pos y biggest {1,0}, //pos z biggest }; //intersection types #define IT_NONE 0 //doesn't touch face at all #define IT_FACE 1 //touches face #define IT_EDGE 2 //touches edge of face #define IT_POINT 3 //touches vertex //see if a point in inside a face by projecting into 2d static uint check_point_to_face(const vms_vector *checkp,segment *sp, side *s,int facenum,int nv,int *vertex_list) { vms_vector_array *checkp_array; vms_vector_array norm; vms_vector t; int biggest; /// int i,j,edge; uint edgemask; fix check_i,check_j; vms_vector_array *v0,*v1; #ifdef COMPACT_SEGS get_side_normal(sp, s-sp->sides, facenum, (vms_vector *)&norm ); #else memcpy( &norm, &s->normals[facenum], sizeof(vms_vector_array)); #endif checkp_array = (vms_vector_array *)checkp; //now do 2d check to see if point is in side //project polygon onto plane by finding largest component of normal t.x = labs(norm.xyz[0]); t.y = labs(norm.xyz[1]); t.z = labs(norm.xyz[2]); if (t.x > t.y) { if (t.x > t.z) biggest=0; else biggest=2; } else { if (t.y > t.z) biggest=1; else biggest=2; } if (norm.xyz[biggest] > 0) { i = ij_table[biggest][0]; j = ij_table[biggest][1]; } else { i = ij_table[biggest][1]; j = ij_table[biggest][0]; } //now do the 2d problem in the i,j plane check_i = checkp_array->xyz[i]; check_j = checkp_array->xyz[j]; for (edge=edgemask=0;edgexyz[i] - v0->xyz[i]; edgevec.j = v1->xyz[j] - v0->xyz[j]; checkvec.i = check_i - v0->xyz[i]; checkvec.j = check_j - v0->xyz[j]; d = fixmul64(checkvec.i,edgevec.j) - fixmul64(checkvec.j,edgevec.i); if (d < 0) //we are outside of triangle edgemask |= (1<>=1),edgenum++); v0 = &Vertices[vertex_list[facenum*3+edgenum]]; v1 = &Vertices[vertex_list[facenum*3+((edgenum+1)%nv)]]; //check if we are touching an edge or point vm_vec_sub(&checkvec,&checkp,v0); edgelen = vm_vec_normalized_dir(&edgevec,v1,v0); //find point dist from planes of ends of edge d = vm_vec_dot(&edgevec,&checkvec); if (d+rad < 0) return IT_NONE; //too far behind start point if (d-rad > edgelen) return IT_NONE; //too far part end point //find closest point on edge to check point itype = IT_POINT; if (d < 0) closest_point = *v0; else if (d > edgelen) closest_point = *v1; else { itype = IT_EDGE; //vm_vec_scale(&edgevec,d); //vm_vec_add(&closest_point,v0,&edgevec); vm_vec_scale_add(&closest_point,v0,&edgevec,d); } dist = vm_vec_dist(&checkp,&closest_point); if (dist <= rad) return (itype==IT_POINT)?IT_NONE:itype; else return IT_NONE; } } //returns true if line intersects with face. fills in newp with intersection //point on plane, whether or not line intersects side //facenum determines which of four possible faces we have //note: the seg parm is temporary, until the face itself has a point field static int check_line_to_face(vms_vector *newp,const vms_vector *p0,const vms_vector *p1,segment *seg,int side,int facenum,int nv,fix rad) { vms_vector checkp; int pli; struct side *s=&seg->sides[side]; int vertex_list[6]; int num_faces; int vertnum; vms_vector norm; #ifdef COMPACT_SEGS get_side_normal(seg, side, facenum, &norm ); #else norm = seg->sides[side].normals[facenum]; #endif create_abs_vertex_lists(&num_faces, vertex_list, seg - Segments, side, __FILE__, __LINE__); //use lowest point number if (num_faces==2) { vertnum = min(vertex_list[0],vertex_list[2]); } else { int i; vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; } pli = find_plane_line_intersection(newp,&Vertices[vertnum],&norm,p0,p1,rad); if (!pli) return IT_NONE; checkp = *newp; //if rad != 0, project the point down onto the plane of the polygon if (rad!=0) vm_vec_scale_add2(&checkp,&norm,-rad); return check_sphere_to_face(&checkp,seg,s,facenum,nv,rad,vertex_list); } //returns the value of a determinant fix calc_det_value(vms_matrix *det) { return fixmul(det->rvec.x,fixmul(det->uvec.y,det->fvec.z)) - fixmul(det->rvec.x,fixmul(det->uvec.z,det->fvec.y)) - fixmul(det->rvec.y,fixmul(det->uvec.x,det->fvec.z)) + fixmul(det->rvec.y,fixmul(det->uvec.z,det->fvec.x)) + fixmul(det->rvec.z,fixmul(det->uvec.x,det->fvec.y)) - fixmul(det->rvec.z,fixmul(det->uvec.y,det->fvec.x)); } //computes the parameters of closest approach of two lines //fill in two parameters, t0 & t1. returns 0 if lines are parallel, else 1 static int check_line_to_line(fix *t1,fix *t2,vms_vector *p1,vms_vector *v1,const vms_vector *p2,vms_vector *v2) { vms_matrix det; fix d,cross_mag2; //mag squared cross product vm_vec_sub(&det.rvec,p2,p1); vm_vec_cross(&det.fvec,v1,v2); cross_mag2 = vm_vec_dot(&det.fvec,&det.fvec); if (cross_mag2 == 0) return 0; //lines are parallel det.uvec = *v2; d = calc_det_value(&det); *t1 = fixdiv(d,cross_mag2); det.uvec = *v1; d = calc_det_value(&det); *t2 = fixdiv(d,cross_mag2); return 1; //found point } //this version is for when the start and end positions both poke through //the plane of a side. In this case, we must do checks against the edge //of faces static int special_check_line_to_face(vms_vector *newp,const vms_vector *p0,const vms_vector *p1,segment *seg,int side,int facenum,int nv,fix rad) { vms_vector move_vec; fix edge_t=0,move_t=0,edge_t2=0,move_t2=0,closest_dist=0; fix edge_len=0,move_len=0; int vertex_list[6]; int num_faces,edgenum; uint edgemask; vms_vector *edge_v0,*edge_v1,edge_vec; struct side *s=&seg->sides[side]; vms_vector closest_point_edge,closest_point_move; //calc some basic stuff create_abs_vertex_lists(&num_faces, vertex_list, seg - Segments, side, __FILE__, __LINE__); vm_vec_sub(&move_vec,p1,p0); //figure out which edge(s) to check against edgemask = check_point_to_face(p0,seg,s,facenum,nv,vertex_list); if (edgemask == 0) return check_line_to_face(newp,p0,p1,seg,side,facenum,nv,rad); for (edgenum=0;!(edgemask&1);edgemask>>=1,edgenum++); edge_v0 = &Vertices[vertex_list[facenum*3+edgenum]]; edge_v1 = &Vertices[vertex_list[facenum*3+((edgenum+1)%nv)]]; vm_vec_sub(&edge_vec,edge_v1,edge_v0); //is the start point already touching the edge? //?? //first, find point of closest approach of vec & edge edge_len = vm_vec_normalize(&edge_vec); move_len = vm_vec_normalize(&move_vec); check_line_to_line(&edge_t,&move_t,edge_v0,&edge_vec,p0,&move_vec); //make sure t values are in valid range if (move_t<0 || move_t>move_len+rad) return IT_NONE; if (move_t > move_len) move_t2 = move_len; else move_t2 = move_t; if (edge_t < 0) //saturate at points edge_t2 = 0; else edge_t2 = edge_t; if (edge_t2 > edge_len) //saturate at points edge_t2 = edge_len; //now, edge_t & move_t determine closest points. calculate the points. vm_vec_scale_add(&closest_point_edge,edge_v0,&edge_vec,edge_t2); vm_vec_scale_add(&closest_point_move,p0,&move_vec,move_t2); //find dist between closest points closest_dist = vm_vec_dist(&closest_point_edge,&closest_point_move); //could we hit with this dist? //note massive tolerance here // if (closest_dist < (rad*18)/20) { //we hit. figure out where if (closest_dist < (rad*15)/20) { //we hit. figure out where //now figure out where we hit vm_vec_scale_add(newp,p0,&move_vec,move_t-rad); return IT_EDGE; } else return IT_NONE; //no hit } //maybe this routine should just return the distance and let the caller //decide it it's close enough to hit //determine if and where a vector intersects with a sphere //vector defined by p0,p1 //returns dist if intersects, and fills in intp //else returns 0 static int check_vector_to_sphere_1(vms_vector *intp,const vms_vector *p0,const vms_vector *p1,vms_vector *sphere_pos,fix sphere_rad) { vms_vector d,dn,w,closest_point; fix mag_d,dist,w_dist,int_dist; //this routine could be optimized if it's taking too much time! vm_vec_sub(&d,p1,p0); vm_vec_sub(&w,sphere_pos,p0); mag_d = vm_vec_copy_normalize(&dn,&d); if (mag_d == 0) { int_dist = vm_vec_mag(&w); *intp = *p0; return (int_dist mag_d+sphere_rad) return 0; //cannot hit vm_vec_scale_add(&closest_point,p0,&dn,w_dist); dist = vm_vec_dist(&closest_point,sphere_pos); if (dist < sphere_rad) { fix dist2,rad2,shorten; dist2 = fixmul(dist,dist); rad2 = fixmul(sphere_rad,sphere_rad); shorten = fix_sqrt(rad2 - dist2); int_dist = w_dist-shorten; if (int_dist > mag_d || int_dist < 0) { //past one or the other end of vector, which means we're inside *intp = *p0; //don't move at all return 1; } vm_vec_scale_add(intp,p0,&dn,int_dist); //calc intersection point return int_dist; } else return 0; } //$$fix get_sphere_int_dist(vms_vector *w,fix dist,fix rad); //$$ //$$#pragma aux get_sphere_int_dist parm [esi] [ebx] [ecx] value [eax] modify exact [eax ebx ecx edx] = //$$ "mov eax,ebx" //$$ "imul eax" //$$ //$$ "mov ebx,eax" //$$ "mov eax,ecx" //$$ "mov ecx,edx" //$$ //$$ "imul eax" //$$ //$$ "sub eax,ebx" //$$ "sbb edx,ecx" //$$ //$$ "call quad_sqrt" //$$ //$$ "push eax" //$$ //$$ "push ebx" //$$ "push ecx" //$$ //$$ "mov eax,[esi]" //$$ "imul eax" //$$ "mov ebx,eax" //$$ "mov ecx,edx" //$$ "mov eax,4[esi]" //$$ "imul eax" //$$ "add ebx,eax" //$$ "adc ecx,edx" //$$ "mov eax,8[esi]" //$$ "imul eax" //$$ "add eax,ebx" //$$ "adc edx,ecx" //$$ //$$ "pop ecx" //$$ "pop ebx" //$$ //$$ "sub eax,ebx" //$$ "sbb edx,ecx" //$$ //$$ "call quad_sqrt" //$$ //$$ "pop ebx" //$$ "sub eax,ebx"; //$$ //$$ //$$//determine if and where a vector intersects with a sphere //$$//vector defined by p0,p1 //$$//returns dist if intersects, and fills in intp. if no intersect, return 0 //$$fix check_vector_to_sphere_2(vms_vector *intp,vms_vector *p0,vms_vector *p1,vms_vector *sphere_pos,fix sphere_rad) //$${ //$$ vms_vector d,w,c; //$$ fix mag_d,dist,mag_c,mag_w; //$$ vms_vector wn,dn; //$$ //$$ vm_vec_sub(&d,p1,p0); //$$ vm_vec_sub(&w,sphere_pos,p0); //$$ //$$ //wn = w; mag_w = vm_vec_normalize(&wn); //$$ //dn = d; mag_d = vm_vec_normalize(&dn); //$$ //$$ mag_w = vm_vec_copy_normalize(&wn,&w); //$$ mag_d = vm_vec_copy_normalize(&dn,&d); //$$ //$$ //vm_vec_cross(&c,&w,&d); //$$ vm_vec_cross(&c,&wn,&dn); //$$ //$$ mag_c = vm_vec_mag(&c); //$$ //mag_d = vm_vec_mag(&d); //$$ //$$ //dist = fixdiv(mag_c,mag_d); //$$ //$$dist = fixmul(mag_c,mag_w); //$$ //$$ if (dist < sphere_rad) { //we intersect. find point of intersection //$$ fix int_dist; //length of vector to intersection point //$$ fix k; //portion of p0p1 we want //$$//@@ fix dist2,rad2,shorten,mag_w2; //$$ //$$//@@ mag_w2 = vm_vec_dot(&w,&w); //the square of the magnitude //$$//@@ //WHAT ABOUT OVERFLOW??? //$$//@@ dist2 = fixmul(dist,dist); //$$//@@ rad2 = fixmul(sphere_rad,sphere_rad); //$$//@@ shorten = fix_sqrt(rad2 - dist2); //$$//@@ int_dist = fix_sqrt(mag_w2 - dist2) - shorten; //$$ //$$ int_dist = get_sphere_int_dist(&w,dist,sphere_rad); //$$ //$$if (labs(int_dist) > mag_d) //I don't know why this would happen //$$ if (int_dist > 0) //$$ k = f1_0; //$$ else //$$ k = -f1_0; //$$else //$$ k = fixdiv(int_dist,mag_d); //$$ //$$// vm_vec_scale(&d,k); //vec from p0 to intersection point //$$// vm_vec_add(intp,p0,&d); //intersection point //$$ vm_vec_scale_add(intp,p0,&d,k); //calc new intersection point //$$ //$$ return int_dist; //$$ } //$$ else //$$ return 0; //no intersection //$$} //determine if a vector intersects with an object //if no intersects, returns 0, else fills in intp and returns dist static fix check_vector_to_object(vms_vector *intp,const vms_vector *p0,const vms_vector *p1,fix rad,object *obj,object *otherobj) { fix size = obj->size; if (obj->type == OBJ_ROBOT && Robot_info[obj->id].attack_type) size = (size*3)/4; //if obj is player, and bumping into other player or a weapon of another coop player, reduce radius if (obj->type == OBJ_PLAYER && ((otherobj->type == OBJ_PLAYER) || ((Game_mode&GM_MULTI_COOP) && otherobj->type == OBJ_WEAPON && otherobj->ctype.laser_info.parent_type == OBJ_PLAYER))) size = size/2; return check_vector_to_sphere_1(intp,p0,p1,&obj->pos,size+rad); } #define MAX_SEGS_VISITED 100 int n_segs_visited; short segs_visited[MAX_SEGS_VISITED]; int fvi_nest_count; //these vars are used to pass vars from fvi_sub() to find_vector_intersection() int fvi_hit_object; // object number of object hit in last find_vector_intersection call. int fvi_hit_seg; // what segment the hit point is in int fvi_hit_side; // what side was hit int fvi_hit_side_seg;// what seg the hitside is in vms_vector wall_norm; //ptr to surface normal of hit wall int fvi_hit_seg2; // what segment the hit point is in static int fvi_sub(vms_vector *intp,int *ints,const vms_vector *p0,int startseg,const vms_vector *p1,fix rad,short thisobjnum,int *ignore_obj_list,int flags,int *seglist,int *n_segs,int entry_seg); //What the hell is fvi_hit_seg for??? //Find out if a vector intersects with anything. //Fills in hit_data, an fvi_info structure (see header file). //Parms: // p0 & startseg describe the start of the vector // p1 the end of the vector // rad the radius of the cylinder // thisobjnum used to prevent an object with colliding with itself // ingore_obj ignore collisions with this object // check_obj_flag determines whether collisions with objects are checked //Returns the hit_data->hit_type int find_vector_intersection(fvi_query *fq,fvi_info *hit_data) { int hit_type,hit_seg,hit_seg2; vms_vector hit_pnt; int i; Assert(fq->ignore_obj_list != (int *)(-1)); Assert((fq->startseg <= Highest_segment_index) && (fq->startseg >= 0)); fvi_hit_seg = -1; fvi_hit_side = -1; fvi_hit_object = -1; //check to make sure start point is in seg its supposed to be in //Assert(check_point_in_seg(p0,startseg,0).centermask==0); //start point not in seg // invalid segnum, so say there is no hit. if(fq->startseg < 0 || fq->startseg > Highest_segment_index) { hit_data->hit_type = HIT_BAD_P0; hit_data->hit_pnt = *fq->p0; hit_data->hit_seg = hit_data->hit_side = hit_data->hit_object = 0; hit_data->hit_side_seg = -1; return hit_data->hit_type; } // Viewer is not in segment as claimed, so say there is no hit. if(!(get_seg_masks(fq->p0,fq->startseg,0,__FILE__,__LINE__).centermask==0)) { hit_data->hit_type = HIT_BAD_P0; hit_data->hit_pnt = *fq->p0; hit_data->hit_seg = fq->startseg; hit_data->hit_side = hit_data->hit_object = 0; hit_data->hit_side_seg = -1; return hit_data->hit_type; } segs_visited[0] = fq->startseg; n_segs_visited=1; fvi_nest_count = 0; hit_seg2 = fvi_hit_seg2 = -1; hit_type = fvi_sub(&hit_pnt,&hit_seg2,fq->p0,fq->startseg,fq->p1,fq->rad,fq->thisobjnum,fq->ignore_obj_list,fq->flags,hit_data->seglist,&hit_data->n_segs,-2); //!!hit_seg = find_point_seg(&hit_pnt,fq->startseg); if (hit_seg2 != -1 && !get_seg_masks(&hit_pnt, hit_seg2, 0, __FILE__, __LINE__).centermask) hit_seg = hit_seg2; else hit_seg = find_point_seg(&hit_pnt,fq->startseg); //MATT: TAKE OUT THIS HACK AND FIX THE BUGS! if (hit_type == HIT_WALL && hit_seg==-1) if (fvi_hit_seg2 != -1 && get_seg_masks(&hit_pnt, fvi_hit_seg2, 0, __FILE__, __LINE__).centermask == 0) hit_seg = fvi_hit_seg2; if (hit_seg == -1) { int new_hit_type; int new_hit_seg2=-1; vms_vector new_hit_pnt; //because of code that deal with object with non-zero radius has //problems, try using zero radius and see if we hit a wall new_hit_type = fvi_sub(&new_hit_pnt,&new_hit_seg2,fq->p0,fq->startseg,fq->p1,0,fq->thisobjnum,fq->ignore_obj_list,fq->flags,hit_data->seglist,&hit_data->n_segs,-2); (void)new_hit_type; // FIXME! This should become hit_type, right? if (new_hit_seg2 != -1) { hit_seg = new_hit_seg2; hit_pnt = new_hit_pnt; } } if (hit_seg!=-1 && fq->flags&FQ_GET_SEGLIST) if (hit_seg != hit_data->seglist[hit_data->n_segs-1] && hit_data->n_segsseglist[hit_data->n_segs++] = hit_seg; if (hit_seg!=-1 && fq->flags&FQ_GET_SEGLIST) for (i=0;in_segs && iseglist[i] == hit_seg) { hit_data->n_segs = i+1; break; } //I'm sorry to say that sometimes the seglist isn't correct. I did my //best. Really. //{ //verify hit list // // int i,ch; // // Assert(hit_data->seglist[0] == startseg); // // for (i=0;in_segs-1;i++) { // for (ch=0;ch<6;ch++) // if (Segments[hit_data->seglist[i]].children[ch] == hit_data->seglist[i+1]) // break; // Assert(ch<6); // } // // Assert(hit_data->seglist[hit_data->n_segs-1] == hit_seg); //} //MATT: PUT THESE ASSERTS BACK IN AND FIX THE BUGS! //!! Assert(hit_seg!=-1); //!! Assert(!((hit_type==HIT_WALL) && (hit_seg == -1))); //When this assert happens, get Matt. Matt: Look at hit_seg2 & //fvi_hit_seg. At least one of these should be set. Why didn't //find_new_seg() find something? // Assert(fvi_hit_seg==-1 || fvi_hit_seg == hit_seg); Assert(!(hit_type==HIT_OBJECT && fvi_hit_object==-1)); hit_data->hit_type = hit_type; hit_data->hit_pnt = hit_pnt; hit_data->hit_seg = hit_seg; hit_data->hit_side = fvi_hit_side; //looks at global hit_data->hit_side_seg = fvi_hit_side_seg; //looks at global hit_data->hit_object = fvi_hit_object; //looks at global hit_data->hit_wallnorm = wall_norm; //looks at global // if(hit_seg != -1 && get_seg_masks(&hit_data->hit_pnt, hit_data->hit_seg, 0, __FILE__, __LINE__).centermask != 0) // Int3(); return hit_type; } //--unused-- fix check_dist(vms_vector *v0,vms_vector *v1) //--unused-- { //--unused-- return vm_vec_dist(v0,v1); //--unused-- } int obj_in_list(int objnum,int *obj_list) { int t; while ((t=*obj_list)!=-1 && t!=objnum) obj_list++; return (t==objnum); } int check_trans_wall(vms_vector *pnt,segment *seg,int sidenum,int facenum); static int fvi_sub(vms_vector *intp,int *ints,const vms_vector *p0,int startseg,const vms_vector *p1,fix rad,short thisobjnum,int *ignore_obj_list,int flags,int *seglist,int *n_segs,int entry_seg) { segment *seg; //the segment we're looking at int startmask,endmask; //mask of faces //@@int sidemask; //mask of sides - can be on back of face but not side int centermask; //where the center point is int objnum; segmasks masks; vms_vector hit_point,closest_hit_point = ZERO_VECTOR; //where we hit fix d,closest_d=0x7fffffff; //distance to hit point int hit_type=HIT_NONE; //what sort of hit int hit_seg=-1; int hit_none_seg=-1; int hit_none_n_segs=0; int hit_none_seglist[MAX_FVI_SEGS]; int cur_nest_level = fvi_nest_count; //fvi_hit_object = -1; if (flags&FQ_GET_SEGLIST) *seglist = startseg; *n_segs=1; seg = &Segments[startseg]; fvi_nest_count++; //first, see if vector hit any objects in this segment if (flags & FQ_CHECK_OBJS) for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next) if ( !(Objects[objnum].flags & OF_SHOULD_BE_DEAD) && !(thisobjnum == objnum ) && (ignore_obj_list==NULL || !obj_in_list(objnum,ignore_obj_list)) && !laser_are_related( objnum, thisobjnum ) && !((thisobjnum > -1) && (CollisionResult[Objects[thisobjnum].type][Objects[objnum].type] == RESULT_NOTHING ) && (CollisionResult[Objects[objnum].type][Objects[thisobjnum].type] == RESULT_NOTHING ))) { int fudged_rad = rad; // If this is a robot:robot collision, only do it if both of them have attack_type != 0 (eg, green guy) if (Objects[thisobjnum].type == OBJ_ROBOT) if (Objects[objnum].type == OBJ_ROBOT) if (!(Robot_info[Objects[objnum].id].attack_type && Robot_info[Objects[thisobjnum].id].attack_type)) continue; if (Objects[thisobjnum].type == OBJ_ROBOT && Robot_info[Objects[thisobjnum].id].attack_type) fudged_rad = (rad*3)/4; //if obj is player, and bumping into other player or a weapon of another coop player, reduce radius if (Objects[thisobjnum].type == OBJ_PLAYER && ((Objects[objnum].type == OBJ_PLAYER) || ((Game_mode&GM_MULTI_COOP) && Objects[objnum].type == OBJ_WEAPON && Objects[objnum].ctype.laser_info.parent_type == OBJ_PLAYER))) fudged_rad = rad/2; //(rad*3)/4; d = check_vector_to_object(&hit_point,p0,p1,fudged_rad,&Objects[objnum],&Objects[thisobjnum]); if (d) //we have intersection if (d < closest_d) { fvi_hit_object = objnum; Assert(fvi_hit_object!=-1); closest_d = d; closest_hit_point = hit_point; hit_type=HIT_OBJECT; } } if ( (thisobjnum > -1 ) && (CollisionResult[Objects[thisobjnum].type][OBJ_WALL] == RESULT_NOTHING ) ) rad = 0; //HACK - ignore when edges hit walls //now, check segment walls startmask = get_seg_masks(p0, startseg, rad, __FILE__, __LINE__).facemask; masks = get_seg_masks(p1, startseg, rad, __FILE__, __LINE__); //on back of which faces? endmask = masks.facemask; //@@sidemask = masks.sidemask; centermask = masks.centermask; if (centermask==0) hit_none_seg = startseg; if (endmask != 0) { //on the back of at least one face int side,bit,face; //for each face we are on the back of, check if intersected for (side=0,bit=1;side<6 && endmask>=bit;side++) { int num_faces; num_faces = get_num_faces(&seg->sides[side]); if (num_faces == 0) num_faces = 1; // commented out by mk on 02/13/94:: if ((num_faces=seg->sides[side].num_faces)==0) num_faces=1; for (face=0;face<2;face++,bit<<=1) { if (endmask & bit) { //on the back of this face int face_hit_type; //in what way did we hit the face? if (seg->children[side] == entry_seg) continue; //don't go back through entry side //did we go through this wall/door? if (startmask & bit) //start was also though. Do extra check face_hit_type = special_check_line_to_face( &hit_point, p0,p1,seg,side, face, ((num_faces==1)?4:3),rad); else //NOTE LINK TO ABOVE!! face_hit_type = check_line_to_face( &hit_point, p0,p1,seg,side, face, ((num_faces==1)?4:3),rad); if (face_hit_type) { //through this wall/door int wid_flag; //if what we have hit is a door, check the adjoining seg if ( (thisobjnum == Players[Player_num].objnum) && (cheats.ghostphysics) ) { wid_flag = WALL_IS_DOORWAY(seg, side); if (seg->children[side] >= 0 ) wid_flag |= WID_FLY_FLAG; } else { wid_flag = WALL_IS_DOORWAY(seg, side); } if ((wid_flag & WID_FLY_FLAG) || ((wid_flag == WID_TRANSPARENT_WALL) && ((flags & FQ_TRANSWALL) || (flags & FQ_TRANSPOINT && check_trans_wall(&hit_point,seg,side,face))))) { int newsegnum; vms_vector sub_hit_point; int sub_hit_type,sub_hit_seg; vms_vector save_wall_norm = wall_norm; int save_hit_objnum=fvi_hit_object; int i; //do the check recursively on the next seg. newsegnum = seg->children[side]; for (i=0;i= MAX_SEGS_VISITED) goto quit_looking; //we've looked a long time, so give up sub_hit_type = fvi_sub(&sub_hit_point,&sub_hit_seg,p0,newsegnum,p1,rad,thisobjnum,ignore_obj_list,flags,temp_seglist,&temp_n_segs,startseg); if (sub_hit_type != HIT_NONE) { d = vm_vec_dist(&sub_hit_point,p0); if (d < closest_d) { closest_d = d; closest_hit_point = sub_hit_point; hit_type = sub_hit_type; if (sub_hit_seg!=-1) hit_seg = sub_hit_seg; //copy seglist if (flags&FQ_GET_SEGLIST) { int ii; for (ii=0;isides[side].normals[face]; #endif if (get_seg_masks(&hit_point, startseg, rad, __FILE__, __LINE__).centermask == 0) hit_seg = startseg; //hit in this segment else fvi_hit_seg2 = startseg; fvi_hit_seg = hit_seg; fvi_hit_side = side; fvi_hit_side_seg = startseg; } } } } } } } // Assert(centermask==0 || hit_seg!=startseg); // Assert(sidemask==0); //Error("Didn't find side we went though"); quit_looking: ; if (hit_type == HIT_NONE) { //didn't hit anything, return end point int i; *intp = *p1; *ints = hit_none_seg; //MATT: MUST FIX THIS!!!! //Assert(!centermask); if (hit_none_seg!=-1) { ///(centermask == 0) if (flags&FQ_GET_SEGLIST) //copy seglist for (i=0;ii = fixdiv(v->i,mag); //--unused-- v->j = fixdiv(v->j,mag); //--unused-- //--unused-- return mag; //--unused-- } #include "textures.h" #include "texmerge.h" #define cross(v0,v1) (fixmul((v0)->i,(v1)->j) - fixmul((v0)->j,(v1)->i)) //finds the uv coords of the given point on the given seg & side //fills in u & v void find_hitpoint_uv(fix *u,fix *v,fix *l,vms_vector *pnt,segment *seg,int sidenum,int facenum) { (void)l; vms_vector_array *pnt_array; vms_vector_array normal_array; int segnum = seg-Segments; int num_faces; int biggest,ii,jj; side *side = &seg->sides[sidenum]; int vertex_list[6],vertnum_list[6]; vec2d p1,vec0,vec1,checkp; //@@,checkv; uvl uvls[3]; fix k0,k1; int i; //do lasers pass through illusory walls? //when do I return 0 & 1 for non-transparent walls? create_abs_vertex_lists(&num_faces, vertex_list, segnum, sidenum, __FILE__, __LINE__); create_all_vertnum_lists(&num_faces,vertnum_list,segnum,sidenum); //now the hard work. //1. find what plane to project this wall onto to make it a 2d case #ifdef COMPACT_SEGS get_side_normal(seg, sidenum, facenum, (vms_vector *)&normal_array ); #else memcpy( &normal_array, &side->normals[facenum], sizeof(vms_vector_array) ); #endif biggest = 0; if (abs(normal_array.xyz[1]) > abs(normal_array.xyz[biggest])) biggest = 1; if (abs(normal_array.xyz[2]) > abs(normal_array.xyz[biggest])) biggest = 2; if (biggest == 0) ii=1; else ii=0; if (biggest == 2) jj=1; else jj=2; //2. compute u,v of intersection point //vec from 1 -> 0 pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+1]]; p1.i = pnt_array->xyz[ii]; p1.j = pnt_array->xyz[jj]; pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+0]]; vec0.i = pnt_array->xyz[ii] - p1.i; vec0.j = pnt_array->xyz[jj] - p1.j; //vec from 1 -> 2 pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+2]]; vec1.i = pnt_array->xyz[ii] - p1.i; vec1.j = pnt_array->xyz[jj] - p1.j; //vec from 1 -> checkpoint pnt_array = (vms_vector_array *)pnt; checkp.i = pnt_array->xyz[ii]; checkp.j = pnt_array->xyz[jj]; //@@checkv.i = checkp.i - p1.i; //@@checkv.j = checkp.j - p1.j; k1 = -fixdiv(cross(&checkp,&vec0) + cross(&vec0,&p1),cross(&vec0,&vec1)); if (vec0.i) k0 = fixdiv(fixmul(-k1,vec1.i) + checkp.i - p1.i,vec0.i); else k0 = fixdiv(fixmul(-k1,vec1.j) + checkp.j - p1.j,vec0.j); for (i=0;i<3;i++) uvls[i] = side->uvls[vertnum_list[facenum*3+i]]; *u = uvls[1].u + fixmul( k0,uvls[0].u - uvls[1].u) + fixmul(k1,uvls[2].u - uvls[1].u); *v = uvls[1].v + fixmul( k0,uvls[0].v - uvls[1].v) + fixmul(k1,uvls[2].v - uvls[1].v); } //check if a particular point on a wall is a transparent pixel //returns 1 if can pass though the wall, else 0 int check_trans_wall(vms_vector *pnt,segment *seg,int sidenum,int facenum) { grs_bitmap *bm; side *side = &seg->sides[sidenum]; int bmx,bmy; fix u,v; Assert(WALL_IS_DOORWAY(seg,sidenum) == WID_TRANSPARENT_WALL); find_hitpoint_uv(&u,&v,NULL,pnt,seg,sidenum,facenum); if (side->tmap_num2 != 0) { bm = texmerge_get_cached_bitmap( side->tmap_num, side->tmap_num2 ); } else { bm = &GameBitmaps[Textures[side->tmap_num].index]; PIGGY_PAGE_IN( Textures[side->tmap_num] ); } if (bm->bm_flags & BM_FLAG_RLE) bm = rle_expand_texture(bm); bmx = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w; bmy = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h; //note: the line above had -v, but that was wrong, so I changed it. if //something doesn't work, and you want to make it negative again, you //should figure out what's going on. return (gr_gpixel (bm, bmx, bmy) == 255); } //new function for Mike //note: n_segs_visited must be set to zero before this is called int sphere_intersects_wall(vms_vector *pnt,int segnum,fix rad,int *hseg,int *hside,int *hface) { int facemask; segment *seg; segs_visited[n_segs_visited++] = segnum; facemask = get_seg_masks(pnt, segnum, rad, __FILE__, __LINE__).facemask; seg = &Segments[segnum]; if (facemask != 0) { //on the back of at least one face int side,bit,face; //for each face we are on the back of, check if intersected for (side=0,bit=1;side<6 && facemask>=bit;side++) { for (face=0;face<2;face++,bit<<=1) { if (facemask & bit) { //on the back of this face int face_hit_type; //in what way did we hit the face? int num_faces,vertex_list[6]; //did we go through this wall/door? create_abs_vertex_lists(&num_faces, vertex_list, seg - Segments, side, __FILE__, __LINE__); face_hit_type = check_sphere_to_face( pnt,seg,&seg->sides[side], face,((num_faces==1)?4:3),rad,vertex_list); if (face_hit_type) { //through this wall/door int child,i; //if what we have hit is a door, check the adjoining seg child = seg->children[side]; for (i=0;ipos,objp->segnum,objp->size,NULL,NULL,NULL); } int object_intersects_wall_d(object *objp,int *hseg,int *hside,int *hface) { n_segs_visited = 0; return sphere_intersects_wall(&objp->pos,objp->segnum,objp->size,hseg,hside,hface); } dxx-rebirth-0.58.1-d1x/main/fvi.h000066400000000000000000000117361217717257200164430ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/fvi.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:42:03 $ * * Header for fvi.c * * $Log: fvi.h,v $ * Revision 1.1.1.1 2006/03/17 19:42:03 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:15 donut * Import of d1x 1.37 source. * * Revision 2.1 1995/03/20 18:15:58 john * Added code to not store the normals in the segment structure. * * Revision 2.0 1995/02/27 11:32:02 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.10 1995/02/02 14:07:58 matt * Fixed confusion about which segment you are touching when you're * touching a wall. This manifested itself in spurious lava burns. * * Revision 1.9 1994/12/04 22:48:04 matt * Physics & FVI now only build seglist for player objects, and they * responsilby deal with buffer full conditions * * Revision 1.8 1994/10/31 12:28:01 matt * Added new function object_intersects_wall() * * Revision 1.7 1994/10/10 13:10:00 matt * Increased max_fvi_segs * * Revision 1.6 1994/09/25 00:38:29 matt * Made the 'find the point in the bitmap where something hit' system * publicly accessible. * * Revision 1.5 1994/08/01 13:30:35 matt * Made fvi() check holes in transparent walls, and changed fvi() calling * parms to take all input data in query structure. * * Revision 1.4 1994/07/13 21:47:59 matt * FVI() and physics now keep lists of segments passed through which the * trigger code uses. * * Revision 1.3 1994/07/08 14:27:26 matt * Non-needed powerups don't get picked up now; this required changing FVI to * take a list of ingore objects rather than just one ignore object. * * Revision 1.2 1994/06/09 09:58:39 matt * Moved find_vector_intersection() from physics.c to new file fvi.c * * Revision 1.1 1994/06/09 09:26:14 matt * Initial revision * * */ #ifndef _FVI_H #define _FVI_H #include "vecmat.h" #include "segment.h" #include "object.h" //return values for find_vector_intersection() - what did we hit? #define HIT_NONE 0 //we hit nothing #define HIT_WALL 1 //we hit - guess - a wall #define HIT_OBJECT 2 //we hit an object - which one? no way to tell... #define HIT_BAD_P0 3 //start point not is specified segment #define MAX_FVI_SEGS 100 //this data structure gets filled in by find_vector_intersection() typedef struct fvi_info { int hit_type; //what sort of intersection vms_vector hit_pnt; //where we hit int hit_seg; //what segment hit_pnt is in int hit_side; //if hit wall, which side int hit_side_seg; //what segment the hit side is in int hit_object; //if object hit, which object vms_vector hit_wallnorm; //if hit wall, ptr to its surface normal int n_segs; //how many segs we went through int seglist[MAX_FVI_SEGS]; //list of segs vector went through } fvi_info; //flags for fvi query #define FQ_CHECK_OBJS 1 //check against objects? #define FQ_TRANSWALL 2 //go through transparent walls #define FQ_TRANSPOINT 4 //go through trans wall if hit point is transparent #define FQ_GET_SEGLIST 8 //build a list of segments //this data contains the parms to fvi() typedef struct fvi_query { const vms_vector *p0,*p1; int startseg; fix rad; short thisobjnum; int *ignore_obj_list; int flags; } fvi_query; //Find out if a vector intersects with anything. //Fills in hit_data, an fvi_info structure (see above). //Parms: // p0 & startseg describe the start of the vector // p1 the end of the vector // rad the radius of the cylinder // thisobjnum used to prevent an object with colliding with itself // ingore_obj_list NULL, or ptr to a list of objnums to ignore, terminated with -1 // check_obj_flag determines whether collisions with objects are checked //Returns the hit_data->hit_type int find_vector_intersection(fvi_query *fq,fvi_info *hit_data); //finds the uv coords of the given point on the given seg & side //fills in u & v void find_hitpoint_uv(fix *u,fix *v,fix *l,vms_vector *pnt,segment *seg,int sidenum,int facenum); //Returns true if the object is through any walls int object_intersects_wall(object *objp); int object_intersects_wall_d(object *objp,int *hseg,int *hside,int *hface); // same as above but more detailed #endif dxx-rebirth-0.58.1-d1x/main/game.c000066400000000000000000001077151217717257200165660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Game loop for Inferno * */ #include #include #include #include #include #include #ifdef OGL #include "ogl_init.h" #endif #include "pstypes.h" #include "console.h" #include "gr.h" #include "inferno.h" #include "game.h" #include "key.h" #include "object.h" #include "physics.h" #include "dxxerror.h" #include "joy.h" #include "iff.h" #include "pcx.h" #include "timer.h" #include "render.h" #include "laser.h" #include "screens.h" #include "textures.h" #include "slew.h" #include "gauges.h" #include "texmap.h" #include "3d.h" #include "effects.h" #include "menu.h" #include "gameseg.h" #include "wall.h" #include "ai.h" #include "hostage.h" #include "fuelcen.h" #include "digi.h" #include "u_mem.h" #include "palette.h" #include "morph.h" #include "lighting.h" #include "newdemo.h" #include "collide.h" #include "weapon.h" #include "sounds.h" #include "args.h" #include "gameseq.h" #include "automap.h" #include "text.h" #include "powerup.h" #include "fireball.h" #include "newmenu.h" #include "gamefont.h" #include "endlevel.h" #include "kconfig.h" #include "config.h" #include "mouse.h" #include "switch.h" #include "controls.h" #include "songs.h" #include "rbaudio.h" #include "multi.h" #include "cntrlcen.h" #include "pcx.h" #include "state.h" #include "piggy.h" #include "multibot.h" #include "fvi.h" #include "playsave.h" #include "hudmsg.h" #include "vers_id.h" #include "event.h" #include "window.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif #ifndef NDEBUG int Mark_count = 0; // number of debugging marks set #endif static fix64 last_timer_value=0; fix ThisLevelTime=0; grs_canvas Screen_3d_window; // The rectangle for rendering the mine to int force_cockpit_redraw=0; int PaletteRedAdd, PaletteGreenAdd, PaletteBlueAdd; // Toggle_var points at a variable which gets !ed on del-T press. int Dummy_var; int *Toggle_var = &Dummy_var; #ifdef EDITOR //flag for whether initial fade-in has been done char faded_in; #endif int Game_suspended=0; //if non-zero, nothing moves but player fix64 Auto_fire_fusion_cannon_time = 0; fix Fusion_charge = 0; int Game_mode = GM_GAME_OVER; int Global_laser_firing_count = 0; int Global_missile_firing_count = 0; fix64 Next_flare_fire_time = 0; // Function prototypes for GAME.C exclusively. void GameProcessFrame(void); void FireLaser(void); void powerup_grab_cheat_all(void); void game_init_render_sub_buffers(int x, int y, int w, int h); // Other functions extern void multi_check_for_killgoal_winner(); extern int ReadControls(d_event *event); // located in gamecntl.c // Cheats game_cheats cheats; // ============================================================================================== //this is called once per game void init_game() { init_objects(); init_special_effects(); init_exploding_walls(); Clear_window = 2; // do portal only window clear. } void reset_palette_add() { PaletteRedAdd = 0; PaletteGreenAdd = 0; PaletteBlueAdd = 0; } u_int32_t Game_screen_mode = SM(640,480); //initialize the various canvases on the game screen //called every time the screen mode or cockpit changes void init_cockpit() { //Initialize the on-screen canvases if (Screen_mode != SCREEN_GAME) return; if ( Screen_mode == SCREEN_EDITOR ) PlayerCfg.CockpitMode[1] = CM_FULL_SCREEN; #ifndef OGL if ( Game_screen_mode != (HiresGFXAvailable? SM(640,480) : SM(320,200)) && PlayerCfg.CockpitMode[1] != CM_LETTERBOX) { PlayerCfg.CockpitMode[1] = CM_FULL_SCREEN; } #endif gr_set_current_canvas(NULL); switch( PlayerCfg.CockpitMode[1] ) { case CM_FULL_COCKPIT: game_init_render_sub_buffers(0, 0, SWIDTH, (SHEIGHT*2)/3); break; case CM_REAR_VIEW: { int x1 = 0, y1 = 0, x2 = SWIDTH, y2 = (SHEIGHT*2)/3; grs_bitmap *bm; PIGGY_PAGE_IN(cockpit_bitmap[PlayerCfg.CockpitMode[1]]); bm = &GameBitmaps[cockpit_bitmap[PlayerCfg.CockpitMode[1]].index]; gr_bitblt_find_transparent_area(bm, &x1, &y1, &x2, &y2); game_init_render_sub_buffers(x1*((float)SWIDTH/bm->bm_w), y1*((float)SHEIGHT/bm->bm_h), (x2-x1+1)*((float)SWIDTH/bm->bm_w), (y2-y1+2)*((float)SHEIGHT/bm->bm_h)); break; } case CM_FULL_SCREEN: game_init_render_sub_buffers(0, 0, SWIDTH, SHEIGHT); break; case CM_STATUS_BAR: game_init_render_sub_buffers( 0, 0, SWIDTH, (HIRESMODE?(SHEIGHT*2)/2.6:(SHEIGHT*2)/2.72) ); break; case CM_LETTERBOX: { int x,y,w,h; x = 0; w = SM_W(Game_screen_mode); h = (SM_H(Game_screen_mode) * 3) / 4; // true letterbox size (16:9) y = (SM_H(Game_screen_mode)-h)/2; gr_rect(x,0,w,SM_H(Game_screen_mode)-h); gr_rect(x,SM_H(Game_screen_mode)-h,w,SM_H(Game_screen_mode)); game_init_render_sub_buffers( x, y, w, h ); break; } } gr_set_current_canvas(NULL); } //selects a given cockpit (or lack of one). See types in game.h void select_cockpit(int mode) { if (mode != PlayerCfg.CockpitMode[1]) { //new mode PlayerCfg.CockpitMode[1]=mode; init_cockpit(); } } //force cockpit redraw next time. call this if you've trashed the screen void reset_cockpit() { force_cockpit_redraw=1; last_drawn_cockpit = -1; } void game_init_render_sub_buffers( int x, int y, int w, int h ) { gr_clear_canvas(0); gr_init_sub_canvas( &Screen_3d_window, &grd_curscreen->sc_canvas, x, y, w, h ); } // Sets up the canvases we will be rendering to void game_init_render_buffers(int render_w, int render_h) { game_init_render_sub_buffers( 0, 0, render_w, render_h ); } //called to change the screen mode. Parameter sm is the new mode, one of //SMODE_GAME or SMODE_EDITOR. returns mode acutally set (could be other //mode if cannot init requested mode) int set_screen_mode(int sm) { if ( (Screen_mode == sm) && !((sm==SCREEN_GAME) && (grd_curscreen->sc_mode != Game_screen_mode)) && !(sm==SCREEN_MENU) ) { gr_set_current_canvas(NULL); return 1; } #ifdef EDITOR Canv_editor = NULL; #endif Screen_mode = sm; switch( Screen_mode ) { case SCREEN_MENU: if (grd_curscreen->sc_mode != Game_screen_mode) if (gr_set_mode(Game_screen_mode)) Error("Cannot set screen mode."); break; case SCREEN_GAME: if (grd_curscreen->sc_mode != Game_screen_mode) if (gr_set_mode(Game_screen_mode)) Error("Cannot set screen mode."); break; #ifdef EDITOR case SCREEN_EDITOR: if (grd_curscreen->sc_mode != SM(800,600)) { int gr_error; if ((gr_error=gr_set_mode(SM(800,600)))!=0) { //force into game scrren Warning("Cannot init editor screen (error=%d)",gr_error); return 0; } } break; #endif default: Error("Invalid screen mode %d",sm); } gr_set_current_canvas(NULL); return 1; } static int time_paused=0; void stop_time() { if (time_paused==0) { fix64 time; timer_update(); time = timer_query(); last_timer_value = time - last_timer_value; if (last_timer_value < 0) { last_timer_value = 0; } } time_paused++; } void start_time() { time_paused--; Assert(time_paused >= 0); if (time_paused==0) { fix64 time; timer_update(); time = timer_query(); last_timer_value = time - last_timer_value; } } void game_flush_inputs() { int dx,dy,dz; event_flush(); key_flush(); joy_flush(); mouse_flush(); mouse_get_delta( &dx, &dy, &dz ); // Read mouse memset(&Controls,0,sizeof(control_info)); } /* * timer that every 50ms sets d_tick_step true and increments d_tick_count */ void calc_d_tick() { static fix timer = 0; d_tick_step = 0; timer += FrameTime; if (timer >= F1_0/20) { d_tick_step = 1; d_tick_count++; if (d_tick_count > 1000000) d_tick_count = 0; timer = (timer-(F1_0/20)); } } void reset_time() { timer_update(); last_timer_value = timer_query(); } void calc_frame_time() { fix64 timer_value; fix last_frametime = FrameTime; timer_update(); timer_value = timer_query(); FrameTime = timer_value - last_timer_value; while (FrameTime < f1_0 / (GameCfg.VSync?MAXIMUM_FPS:GameArg.SysMaxFPS)) { if (GameArg.SysUseNiceFPS && !GameCfg.VSync) timer_delay(f1_0 / GameArg.SysMaxFPS - FrameTime); timer_update(); timer_value = timer_query(); FrameTime = timer_value - last_timer_value; } if ( cheats.turbo ) FrameTime *= 2; last_timer_value = timer_value; if (FrameTime < 0) //if bogus frametime... FrameTime = (last_frametime==0?1:last_frametime); //...then use time from last frame GameTime64 += FrameTime; calc_d_tick(); } void move_player_2_segment(segment *seg,int side) { vms_vector vp; compute_segment_center(&ConsoleObject->pos,seg); compute_center_point_on_side(&vp,seg,side); vm_vec_sub2(&vp,&ConsoleObject->pos); vm_vector_2_matrix(&ConsoleObject->orient,&vp,NULL,NULL); obj_relink( ConsoleObject-Objects, SEG_PTR_2_NUM(seg) ); } void do_photos(); void level_with_floor(); #ifndef OGL void save_screen_shot(int automap_flag) { grs_canvas *screen_canv=&grd_curscreen->sc_canvas; static int savenum=0; grs_canvas *temp_canv,*save_canv; char savename[FILENAME_LEN+sizeof(SCRNS_DIR)]; ubyte pal[768]; stop_time(); if (!PHYSFSX_exists(SCRNS_DIR,0)) PHYSFS_mkdir(SCRNS_DIR); //try making directory save_canv = grd_curcanv; temp_canv = gr_create_canvas(screen_canv->cv_bitmap.bm_w,screen_canv->cv_bitmap.bm_h); gr_set_current_canvas(temp_canv); gr_ubitmap(0,0,&screen_canv->cv_bitmap); gr_set_current_canvas(save_canv); do { sprintf(savename, "%sscrn%04d.pcx",SCRNS_DIR, savenum++); } while (PHYSFSX_exists(savename,0)); gr_set_current_canvas(NULL); if (!automap_flag) HUD_init_message(HM_DEFAULT, "%s 'scrn%04d.pcx'", TXT_DUMPING_SCREEN, savenum-1 ); gr_palette_read(pal); //get actual palette from the hardware pcx_write_bitmap(savename,&temp_canv->cv_bitmap,pal); gr_set_current_canvas(screen_canv); gr_ubitmap(0,0,&temp_canv->cv_bitmap); gr_free_canvas(temp_canv); gr_set_current_canvas(save_canv); start_time(); } #endif //initialize flying void fly_init(object *obj) { obj->control_type = CT_FLYING; obj->movement_type = MT_PHYSICS; vm_vec_zero(&obj->mtype.phys_info.velocity); vm_vec_zero(&obj->mtype.phys_info.thrust); vm_vec_zero(&obj->mtype.phys_info.rotvel); vm_vec_zero(&obj->mtype.phys_info.rotthrust); } void test_anim_states(); extern int been_in_editor; // ------------------------------------------------------------------------------------ void do_cloak_stuff(void) { int i; for (i = 0; i < N_players; i++) if (Players[i].flags & PLAYER_FLAGS_CLOAKED) { if (GameTime64 > Players[i].cloak_time+CLOAK_TIME_MAX) { Players[i].flags &= ~PLAYER_FLAGS_CLOAKED; if (i == Player_num) { digi_play_sample( SOUND_CLOAK_OFF, F1_0); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_CLOAK_OFF, F1_0); maybe_drop_net_powerup(POW_CLOAK); if ( Newdemo_state != ND_STATE_PLAYBACK ) multi_send_decloak(); // For demo recording #endif } } } } int FakingInvul=0; // ------------------------------------------------------------------------------------ void do_invulnerable_stuff(void) { if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) { if (GameTime64 > Players[Player_num].invulnerable_time+INVULNERABLE_TIME_MAX) { Players[Player_num].flags ^= PLAYER_FLAGS_INVULNERABLE; if (FakingInvul==0) { digi_play_sample( SOUND_INVULNERABILITY_OFF, F1_0); #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_play_sound(SOUND_INVULNERABILITY_OFF, F1_0); maybe_drop_net_powerup(POW_INVULNERABILITY); } #endif } FakingInvul=0; } } } // Amount to diminish guns towards normal, per second. #define DIMINISH_RATE 16 // gots to be a power of 2, else change the code in diminish_palette_towards_normal //adds to rgb values for palette flash void PALETTE_FLASH_ADD(int _dr, int _dg, int _db) { int maxval; PaletteRedAdd += _dr; PaletteGreenAdd += _dg; PaletteBlueAdd += _db; maxval = MAX_PALETTE_ADD; if (PaletteRedAdd > maxval) PaletteRedAdd = maxval; if (PaletteGreenAdd > maxval) PaletteGreenAdd = maxval; if (PaletteBlueAdd > maxval) PaletteBlueAdd = maxval; if (PaletteRedAdd < -maxval) PaletteRedAdd = -maxval; if (PaletteGreenAdd < -maxval) PaletteGreenAdd = -maxval; if (PaletteBlueAdd < -maxval) PaletteBlueAdd = -maxval; } // ------------------------------------------------------------------------------------ // Diminish palette effects towards normal. void diminish_palette_towards_normal(void) { int dec_amount = 0; // Diminish at DIMINISH_RATE units/second. // For frame rates > DIMINISH_RATE Hz, use randomness to achieve this. if (FrameTime < F1_0/DIMINISH_RATE) { if (d_rand() < FrameTime*DIMINISH_RATE/2) // Note: d_rand() is in 0..32767, and 8 Hz means decrement every frame dec_amount = 1; } else { dec_amount = f2i(FrameTime*DIMINISH_RATE); // one second = DIMINISH_RATE counts if (dec_amount == 0) dec_amount++; // make sure we decrement by something } if (PaletteRedAdd > 0 ) { PaletteRedAdd -= dec_amount; if (PaletteRedAdd < 0 ) PaletteRedAdd = 0; } if (PaletteRedAdd < 0 ) { PaletteRedAdd += dec_amount; if (PaletteRedAdd > 0 ) PaletteRedAdd = 0; } if (PaletteGreenAdd > 0 ) { PaletteGreenAdd -= dec_amount; if (PaletteGreenAdd < 0 ) PaletteGreenAdd = 0; } if (PaletteGreenAdd < 0 ) { PaletteGreenAdd += dec_amount; if (PaletteGreenAdd > 0 ) PaletteGreenAdd = 0; } if (PaletteBlueAdd > 0 ) { PaletteBlueAdd -= dec_amount; if (PaletteBlueAdd < 0 ) PaletteBlueAdd = 0; } if (PaletteBlueAdd < 0 ) { PaletteBlueAdd += dec_amount; if (PaletteBlueAdd > 0 ) PaletteBlueAdd = 0; } if ( (Newdemo_state==ND_STATE_RECORDING) && (PaletteRedAdd || PaletteGreenAdd || PaletteBlueAdd) ) newdemo_record_palette_effect(PaletteRedAdd, PaletteGreenAdd, PaletteBlueAdd); gr_palette_step_up( PaletteRedAdd, PaletteGreenAdd, PaletteBlueAdd ); } int Redsave, Bluesave, Greensave; void palette_save(void) { Redsave = PaletteRedAdd; Bluesave = PaletteBlueAdd; Greensave = PaletteGreenAdd; } void palette_restore(void) { PaletteRedAdd = Redsave; PaletteBlueAdd = Bluesave; PaletteGreenAdd = Greensave; gr_palette_step_up( PaletteRedAdd, PaletteGreenAdd, PaletteBlueAdd ); } extern void dead_player_frame(void); // -------------------------------------------------------------------------------------------------- int allowed_to_fire_laser(void) { if (Player_is_dead) { Global_missile_firing_count = 0; return 0; } // Make sure enough time has elapsed to fire laser if (Next_laser_fire_time > GameTime64) return 0; return 1; } int allowed_to_fire_flare(void) { if (Next_flare_fire_time > GameTime64) return 0; Next_flare_fire_time = GameTime64 + F1_0/4; return 1; } int allowed_to_fire_missile(void) { // Make sure enough time has elapsed to fire missile if (Next_missile_fire_time > GameTime64) return 0; return 1; } extern int Death_sequence_aborted; #ifdef USE_SDLMIXER #define EXT_MUSIC_TEXT "Jukebox/Audio CD" #else #define EXT_MUSIC_TEXT "Audio CD" #endif static int free_help(newmenu *menu, d_event *event, void *userdata) { userdata = userdata; if (event->type == EVENT_WINDOW_CLOSE) { newmenu_item *items = newmenu_get_items(menu); d_free(items); } return 0; } void show_help() { int nitems = 0; newmenu_item *m; MALLOC(m, newmenu_item, 26); if (!m) return; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_ESC; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "SHIFT-ESC\t SHOW GAME LOG"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F1\t THIS SCREEN"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_F2; #if !(defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F2/F3\t SAVE/LOAD GAME"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F1\t Fast Save"; #else m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F2/F3 (\x85-SHIFT-s/\x85-o)\t SAVE/LOAD GAME"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F1 (\x85-s)\t Fast Save"; #endif m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F3\t SWITCH COCKPIT MODES"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_F5; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "ALT-F7\t SWITCH HUD MODES"; #if !(defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_PAUSE; #else m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Pause (\x85-P)\t Pause"; #endif m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_PRTSCN; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_1TO5; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_6TO10; #if !(defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-Shift-F9\t Eject Audio CD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-Shift-F10\t Play/Pause " EXT_MUSIC_TEXT; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-Shift-F11/F12\t Previous/Next Song"; #else m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "\x85-E\t Eject Audio CD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "\x85-Up/Down\t Play/Pause " EXT_MUSIC_TEXT; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "\x85-Left/Right\t Previous/Next Song"; #endif #if (defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "(Use \x85-# for F#. e.g. \x85-1 for F1)"; #endif newmenu_dotiny( NULL, TXT_KEYS, nitems, m, 0, free_help, NULL ); } void show_netgame_help() { int nitems = 0; newmenu_item *m; MALLOC(m, newmenu_item, 16); if (!m) return; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F1\t THIS SCREEN"; #if !(defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F2/F3\t SAVE/LOAD COOP GAME"; #else m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "Alt-F2/F3 (\x85-SHIFT-s/\x85-o)\t SAVE/LOAD COOP GAME"; #endif m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "ALT-F4\t SHOW PLAYER NAMES ON HUD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F7\t TOGGLE KILL LIST"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F8\t SEND MESSAGE"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "(SHIFT-)F9 to F12\t (DEFINE)SEND MACRO"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "PAUSE\t SHOW NETGAME INFORMATION"; #if (defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "(Use \x85-# for F#. e.g. \x85-1 for F1)"; #endif m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "MULTIPLAYER MESSAGE COMMANDS:"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "(*): TEXT\t SEND TEXT TO PLAYER/TEAM (*)"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "/Handicap: (*)\t SET YOUR STARTING SHIELDS TO (*) [10-100]"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "/move: (*)\t MOVE PLAYER (*) TO OTHER TEAM (Host-only)"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "/kick: (*)\t KICK PLAYER (*) FROM GAME (Host-only)"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "/KillReactor\t BLOW UP THE MINE (Host-only)"; newmenu_dotiny( NULL, TXT_KEYS, nitems, m, 0, free_help, NULL ); } void show_newdemo_help() { newmenu_item *m; int nitems = 0; MALLOC(m, newmenu_item, 15); if (!m) return; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "ESC\t QUIT DEMO PLAYBACK"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F1\t THIS SCREEN"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = TXT_HELP_F2; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F3\t SWITCH COCKPIT MODES"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "F4\t TOGGLE PERCENTAGE DISPLAY"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "UP\t PLAY"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "DOWN\t PAUSE"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "RIGHT\t ONE FRAME FORWARD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "LEFT\t ONE FRAME BACKWARD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "SHIFT-RIGHT\t FAST FORWARD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "SHIFT-LEFT\t FAST BACKWARD"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "CTRL-RIGHT\t JUMP TO END"; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "CTRL-LEFT\t JUMP TO START"; #if (defined(__APPLE__) || defined(macintosh)) m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "(Use \x85-# for F#. e.g. \x85-1 for F1)"; #endif newmenu_dotiny( NULL, "DEMO PLAYBACK CONTROLS", nitems, m, 0, free_help, NULL ); } //temp function until Matt cleans up game sequencing extern void temp_reset_stuff_on_level(); #define LEAVE_TIME 0x4000 //how long until we decide key is down (Used to be 0x4000) //deal with rear view - switch it on, or off, or whatever void check_rear_view() { static int leave_mode; static fix64 entry_time; if (Newdemo_state == ND_STATE_PLAYBACK) return; if ( Controls.rear_view_count > 0) { //key/button has gone down Controls.rear_view_count = 0; if (Rear_view) { Rear_view = 0; if (PlayerCfg.CockpitMode[1]==CM_REAR_VIEW) { select_cockpit(PlayerCfg.CockpitMode[0]); } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_restore_rearview(); } else { Rear_view = 1; leave_mode = 0; //means wait for another key entry_time = timer_query(); if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) { select_cockpit(CM_REAR_VIEW); } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_rearview(); } } else if (Controls.rear_view_state) { if (leave_mode == 0 && (timer_query() - entry_time) > LEAVE_TIME) leave_mode = 1; } else { if (leave_mode==1 && Rear_view) { Rear_view = 0; if (PlayerCfg.CockpitMode[1]==CM_REAR_VIEW) { select_cockpit(PlayerCfg.CockpitMode[0]); } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_restore_rearview(); } } } void reset_rear_view(void) { if (Rear_view) { if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_restore_rearview(); } Rear_view = 0; select_cockpit(PlayerCfg.CockpitMode[0]); } int Config_menu_flag; void game_disable_cheats() { memset(&cheats, 0, sizeof(cheats)); } // game_setup() // ---------------------------------------------------------------------------- int game_handler(window *wind, d_event *event, void *data); extern int netplayerinfo_on; window *game_setup(void) { window *game_wind; PlayerCfg.CockpitMode[1] = PlayerCfg.CockpitMode[0]; last_drawn_cockpit = -1; // Force cockpit to redraw next time a frame renders. Endlevel_sequence = 0; game_wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, game_handler, NULL); if (!game_wind) return NULL; reset_palette_add(); init_cockpit(); init_gauges(); netplayerinfo_on = 0; #ifdef EDITOR if (!Cursegp) { Cursegp = &Segments[0]; Curside = 0; } if (Segments[ConsoleObject->segnum].segnum == -1) //segment no longer exists obj_relink( ConsoleObject-Objects, SEG_PTR_2_NUM(Cursegp) ); if (!check_obj_seg(ConsoleObject)) move_player_2_segment(Cursegp,Curside); #endif Viewer = ConsoleObject; fly_init(ConsoleObject); Game_suspended = 0; reset_time(); FrameTime = 0; //make first frame zero #ifdef EDITOR if (Current_level_num == 0) { //not a real level init_player_stats_game(Player_num); init_ai_objects(); } #endif fix_object_segs(); return game_wind; } void game_render_frame(); window *Game_wind = NULL; // Event handler for the game int game_handler(window *wind, d_event *event, void *data) { data = data; switch (event->type) { case EVENT_WINDOW_ACTIVATED: set_screen_mode(SCREEN_GAME); event_toggle_focus(1); key_toggle_repeat(0); game_flush_inputs(); if (time_paused) start_time(); if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) digi_resume_digi_sounds(); if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) palette_restore(); reset_cockpit(); break; case EVENT_WINDOW_DEACTIVATED: if (!(((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK)) && (!Endlevel_sequence)) ) stop_time(); if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) digi_pause_digi_sounds(); if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) palette_save(); event_toggle_focus(0); key_toggle_repeat(1); break; case EVENT_JOYSTICK_BUTTON_UP: case EVENT_JOYSTICK_BUTTON_DOWN: case EVENT_JOYSTICK_MOVED: case EVENT_MOUSE_BUTTON_UP: case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_MOVED: case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: case EVENT_IDLE: return ReadControls(event); case EVENT_WINDOW_DRAW: if (!time_paused) { calc_frame_time(); GameProcessFrame(); } if (!Automap_active) // efficiency hack { if (force_cockpit_redraw) { //screen need redrawing? init_cockpit(); force_cockpit_redraw=0; } game_render_frame(); } break; case EVENT_WINDOW_CLOSE: digi_stop_digi_sounds(); if ( (Newdemo_state == ND_STATE_RECORDING) || (Newdemo_state == ND_STATE_PAUSED) ) newdemo_stop_recording(); #ifdef NETWORK multi_leave_game(); #endif if ( Newdemo_state == ND_STATE_PLAYBACK ) newdemo_stop_playback(); songs_play_song( SONG_TITLE, 1 ); game_disable_cheats(); Game_mode = GM_GAME_OVER; #ifdef EDITOR if (!EditorWindow) // have to do it this way because of the necessary longjmp. Yuck. #endif show_menus(); Game_wind = NULL; event_toggle_focus(0); key_toggle_repeat(1); break; case EVENT_WINDOW_CLOSED: longjmp(LeaveEvents, 0); break; default: break; } return 0; } // Initialise game, actually runs in main event loop void game() { hide_menus(); Game_wind = game_setup(); } //called at the end of the program void close_game() { close_gauges(); restore_effect_bitmap_icons(); } #ifdef EDITOR extern void player_follow_path(object *objp); extern void check_create_player_path(void); #endif extern int Do_appearance_effect; void game_leave_menus(void) { window *wind; if (!Game_wind) return; while ((wind = window_get_front()) && (wind != Game_wind)) // go through all windows and actually close them if they want to window_close(wind); } void GameProcessFrame(void) { fix player_shields = Players[Player_num].shields; int player_was_dead = Player_is_dead; update_player_stats(); diminish_palette_towards_normal(); // Should leave palette effect up for as long as possible by putting right before render. do_cloak_stuff(); do_invulnerable_stuff(); remove_obsolete_stuck_objects(); #ifdef EDITOR check_create_player_path(); player_follow_path(ConsoleObject); #endif #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_do_frame(); if (Netgame.PlayTimeAllowed && ThisLevelTime>=i2f((Netgame.PlayTimeAllowed*5*60))) multi_check_for_killgoal_winner(); } #endif dead_player_frame(); if (Newdemo_state != ND_STATE_PLAYBACK) do_controlcen_dead_frame(); #ifdef NETWORK if ((Game_mode & GM_MULTI) && Netgame.PlayTimeAllowed) ThisLevelTime +=FrameTime; #endif digi_sync_sounds(); if (Endlevel_sequence) { do_endlevel_frame(); powerup_grab_cheat_all(); do_special_effects(); return; //skip everything else } if (Newdemo_state != ND_STATE_PLAYBACK) do_exploding_wall_frame(); if ((Newdemo_state != ND_STATE_PLAYBACK) || (Newdemo_vcr_state != ND_STATE_PAUSED)) { do_special_effects(); wall_frame_process(); triggers_frame_process(); } if (Control_center_destroyed) { if (Newdemo_state==ND_STATE_RECORDING ) newdemo_record_control_center_destroyed(); } flash_frame(); if ( Newdemo_state == ND_STATE_PLAYBACK ) { newdemo_playback_one_frame(); if ( Newdemo_state != ND_STATE_PLAYBACK ) { if (Game_wind) window_close(Game_wind); // Go back to menu return; } } else { // Note the link to above! Players[Player_num].homing_object_dist = -1; // Assume not being tracked. Laser_do_weapon_sequence modifies this. object_move_all(); powerup_grab_cheat_all(); if (Endlevel_sequence) //might have been started during move return; fuelcen_update_all(); do_ai_frame_all(); if (allowed_to_fire_laser()) FireLaser(); // Fire Laser! if (Auto_fire_fusion_cannon_time) { if (Primary_weapon != FUSION_INDEX) Auto_fire_fusion_cannon_time = 0; else if (GameTime64 + FrameTime/2 >= Auto_fire_fusion_cannon_time) { Auto_fire_fusion_cannon_time = 0; Global_laser_firing_count = 1; } else if (d_tick_step) { vms_vector rand_vec; fix bump_amount; Global_laser_firing_count = 0; ConsoleObject->mtype.phys_info.rotvel.x += (d_rand() - 16384)/8; ConsoleObject->mtype.phys_info.rotvel.z += (d_rand() - 16384)/8; make_random_vector(&rand_vec); bump_amount = F1_0*4; if (Fusion_charge > F1_0*2) bump_amount = Fusion_charge*4; bump_one_object(ConsoleObject, &rand_vec, bump_amount); } else { Global_laser_firing_count = 0; } } if (Global_laser_firing_count) Global_laser_firing_count -= do_laser_firing_player(); if (Global_laser_firing_count < 0) Global_laser_firing_count = 0; } if (Do_appearance_effect) { create_player_appearance_effect(ConsoleObject); Do_appearance_effect = 0; #ifdef NETWORK if ((Game_mode & GM_MULTI) && Netgame.InvulAppear) { Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE; Players[Player_num].invulnerable_time = GameTime64-i2f(27); FakingInvul=1; } #endif } // Check if we have to close in-game menus for multiplayer if ((Game_mode & GM_MULTI) && (Players[Player_num].connected == CONNECT_PLAYING)) { if ( Endlevel_sequence || ((Control_center_destroyed) && (Countdown_seconds_left <= 1)) || // close menus when end of level... (Automap_active && ((Player_is_dead != player_was_dead) || (Players[Player_num].shields<=0 && player_shields>0))) ) // close autmap when dying ... game_leave_menus(); } } // ----------------------------------------------------------------------------- // Fire Laser: Registers a laser fire, and performs special stuff for the fusion // cannon. void FireLaser() { Global_laser_firing_count = Controls.fire_primary_state?Weapon_info[Primary_weapon_to_weapon_info[Primary_weapon]].fire_count:0; if ((Primary_weapon == FUSION_INDEX) && (Global_laser_firing_count)) { if ((Players[Player_num].energy < F1_0*2) && (Auto_fire_fusion_cannon_time == 0)) { Global_laser_firing_count = 0; } else { static fix64 Fusion_next_sound_time = 0; if (Fusion_charge == 0) Players[Player_num].energy -= F1_0*2; Fusion_charge += FrameTime; Players[Player_num].energy -= FrameTime; if (Players[Player_num].energy <= 0) { Players[Player_num].energy = 0; Auto_fire_fusion_cannon_time = GameTime64 -1; // Fire now! } else Auto_fire_fusion_cannon_time = GameTime64 + FrameTime/2 + 1; // Fire the fusion cannon at this time in the future. if (Fusion_charge < F1_0*2) PALETTE_FLASH_ADD(Fusion_charge >> 11, 0, Fusion_charge >> 11); else PALETTE_FLASH_ADD(Fusion_charge >> 11, Fusion_charge >> 11, 0); if (Fusion_next_sound_time > GameTime64 + F1_0/8 + D_RAND_MAX/4) // GameTime64 is smaller than max delay - player in new level? Fusion_next_sound_time = GameTime64 - 1; if (Fusion_next_sound_time < GameTime64) { if (Fusion_charge > F1_0*2) { digi_play_sample( 11, F1_0 ); #ifdef NETWORK if(Game_mode & GM_MULTI) multi_send_play_sound(11, F1_0); #endif apply_damage_to_player(ConsoleObject, ConsoleObject, d_rand() * 4, 0); } else { create_awareness_event(ConsoleObject, PA_WEAPON_ROBOT_COLLISION); digi_play_sample( SOUND_FUSION_WARMUP, F1_0 ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_play_sound(SOUND_FUSION_WARMUP, F1_0); #endif } Fusion_next_sound_time = GameTime64 + F1_0/8 + d_rand()/4; } } } } // ------------------------------------------------------------------------------------------------------- // If player is close enough to objnum, which ought to be a powerup, pick it up! // This could easily be made difficulty level dependent. void powerup_grab_cheat(object *player, int objnum) { fix powerup_size; fix player_size; fix dist; Assert(Objects[objnum].type == OBJ_POWERUP); powerup_size = Objects[objnum].size; player_size = player->size; dist = vm_vec_dist_quick(&Objects[objnum].pos, &player->pos); if ((dist < 2*(powerup_size + player_size)) && !(Objects[objnum].flags & OF_SHOULD_BE_DEAD)) { vms_vector collision_point; vm_vec_avg(&collision_point, &Objects[objnum].pos, &player->pos); collide_player_and_powerup(player, &Objects[objnum], &collision_point); } } // ------------------------------------------------------------------------------------------------------- // Make it easier to pick up powerups. // For all powerups in this segment, pick them up at up to twice pickuppable distance based on dot product // from player to powerup and player's forward vector. // This has the effect of picking them up more easily left/right and up/down, but not making them disappear // way before the player gets there. void powerup_grab_cheat_all(void) { segment *segp; int objnum; segp = &Segments[ConsoleObject->segnum]; objnum = segp->objects; while (objnum != -1) { if (Objects[objnum].type == OBJ_POWERUP) powerup_grab_cheat(ConsoleObject, objnum); objnum = Objects[objnum].next; } } int Last_level_path_created = -1; #ifdef SHOW_EXIT_PATH // ------------------------------------------------------------------------------------------------------------------ // Create path for player from current segment to goal segment. // Return true if path created, else return false. int mark_player_path_to_segment(int segnum) { int i; object *objp = ConsoleObject; short player_path_length=0; int player_hide_index=-1; if (Last_level_path_created == Current_level_num) { return 0; } Last_level_path_created = Current_level_num; if (create_path_points(objp, objp->segnum, segnum, Point_segs_free_ptr, &player_path_length, 100, 0, 0, -1) == -1) { return 0; } player_hide_index = Point_segs_free_ptr - Point_segs; Point_segs_free_ptr += player_path_length; if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) { ai_reset_all_paths(); return 0; } for (i=1; irtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num; obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time; obj->rtype.vclip_info.framenum = 0; obj->lifeleft = F1_0*100 + d_rand() * 4; } return 1; } // Return true if it happened, else return false. int create_special_path(void) { int i,j; // ---------- Find exit doors ---------- for (i=0; i<=Highest_segment_index; i++) for (j=0; j Max_obj_count_mike) { Max_obj_count_mike = count; } } } #endif dxx-rebirth-0.58.1-d1x/main/game.h000066400000000000000000000150441217717257200165640ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Constants & prototypes which pertain to the game only * */ #ifndef _GAME_H #define _GAME_H #include "physfsx.h" #include "pstypes.h" #include "window.h" #include "vecmat.h" #ifdef NDEBUG #define MAXIMUM_FPS 200 #else #define MAXIMUM_FPS 1000 #endif struct object; extern struct window *Game_wind; // from mglobal.c extern fix FrameTime; // time in seconds since last frame extern fix64 GameTime64; // time in game (sum of FrameTime) extern int d_tick_count; // increments every 50ms extern int d_tick_step; // true once every 50ms extern fix64 Next_laser_fire_time; // Time at which player can next fire his selected laser. extern fix64 Last_laser_fired_time; extern fix64 Next_missile_fire_time; // Time at which player can next fire his selected missile. extern fix64 Next_flare_fire_time; extern fix Laser_delay_time; // Delay between laser fires. // constants for ft_preference #define FP_RIGHT 0 #define FP_UP 1 #define FP_FORWARD 2 // this is the default #define FP_LEFT 3 #define FP_DOWN 4 #define FP_FIRST_TIME 5 extern int ft_preference; // The following bits define the game modes. #define GM_EDITOR 1 // You came into the game from the editor // #define GM_SERIAL 2 // You are in serial mode // OBSOLETE #define GM_NETWORK 4 // You are in network mode #define GM_MULTI_ROBOTS 8 // You are in a multiplayer mode with robots. #define GM_MULTI_COOP 16 // You are in a multiplayer mode and can't hurt other players. // #define GM_MODEM 32 // You are in a modem (serial) game // OBSOLETE #define GM_UNKNOWN 64 // You are not in any mode, kind of dangerous... #define GM_GAME_OVER 128 // Game has been finished #define GM_TEAM 256 // Team mode for network play #define GM_BOUNTY 512 // New bounty mode by Matt1360 #define GM_NORMAL 0 // You are in normal play mode, no multiplayer stuff #define GM_MULTI 38 // You are in some type of multiplayer game #define NDL 5 // Number of difficulty levels. extern int Game_mode; extern u_int32_t Game_screen_mode; extern int gauge_message_on; #ifndef NDEBUG // if debugging, these are variables extern int Slew_on; // in slew or sim mode? #else // if not debugging, these are constants #define Slew_on 0 // no slewing in real game #define Game_double_buffer 1 // always double buffer in real game #endif // Suspend flags #define SUSP_NONE 0 // Everything moving normally #define SUSP_ROBOTS 1 // Robot AI doesn't move #define SUSP_WEAPONS 2 // Lasers, etc. don't move extern int Game_suspended; // if non-zero, nothing moves but player #define SHOW_EXIT_PATH 1 // from game.c void init_game(void); void game(void); void close_game(void); void init_cockpit(void); void calc_frame_time(void); void calc_d_tick(); int do_flythrough(struct object *obj,int first_time); extern int Difficulty_level; // Difficulty level in 0..NDL-1, 0 = easiest, NDL-1 = hardest extern int Global_laser_firing_count; extern int Global_missile_firing_count; extern int Render_depth; extern fix64 Auto_fire_fusion_cannon_time; extern fix Fusion_charge; extern int PaletteRedAdd, PaletteGreenAdd, PaletteBlueAdd; #define MAX_PALETTE_ADD 30 extern void PALETTE_FLASH_ADD(int dr, int dg, int db); //sets the rgb values for palette flash #define PALETTE_FLASH_SET(_r,_g,_b) PaletteRedAdd=(_r), PaletteGreenAdd=(_g), PaletteBlueAdd=(_b) extern int draw_gauges_on; extern void init_game_screen(void); extern void game_flush_inputs(); // clear all inputs extern int Playing_game; // True if playing game extern int Auto_flythrough; // if set, start flythough automatically extern int Mark_count; // number of debugging marks set extern char faded_in; extern int last_drawn_cockpit; extern void stop_time(void); extern void start_time(void); extern void reset_time(void); // called when starting level // If automap_flag == 1, then call automap routine to write message. extern void save_screen_shot(int automap_flag); //valid modes for cockpit #define CM_FULL_COCKPIT 0 // normal screen with cockput #define CM_REAR_VIEW 1 // looking back with bitmap #define CM_STATUS_BAR 2 // small status bar, w/ reticle #define CM_FULL_SCREEN 3 // full screen, no cockpit (w/ reticle) #define CM_LETTERBOX 4 // half-height window (for cutscenes) extern int Game_window_w, // width and height of player's game window Game_window_h; extern int Rear_view; // if true, looking back. // initalize flying void fly_init(struct object *obj); // selects a given cockpit (or lack of one). void select_cockpit(int mode); // force cockpit redraw next time. call this if you've trashed the screen void reset_cockpit(void); // called if you've trashed the screen // functions to save, clear, and resture palette flash effects void palette_save(void); void reset_palette_add(void); void palette_restore(void); // put up the help message void show_help(); void show_netgame_help(); void show_newdemo_help(); // show a message in a nice little box void show_boxed_message(char *msg, int RenderFlag); // turns off rear view & rear view cockpit void reset_rear_view(void); void game_init_render_buffers (int render_max_w, int render_max_h); void game_render_frame_mono(int flip); void game_leave_menus(void); //Cheats typedef struct game_cheats { int enabled; int wowie; int wowie2; int allkeys; int invul; int cloak; int shields; int extralife; int killreactor; int exitpath; int levelwarp; int fullautomap; int ghostphysics; int rapidfire; int turbo; int robotfiringsuspended; int baldguy; int acid; } __pack__ game_cheats; extern game_cheats cheats; void game_disable_cheats(); #endif dxx-rebirth-0.58.1-d1x/main/gamecntl.c000066400000000000000000001022121217717257200174320ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Game Controls Stuff * */ //#define DOOR_DEBUGGING #include #include #include #include #include "pstypes.h" #include "window.h" #include "console.h" #include "inferno.h" #include "game.h" #include "player.h" #include "key.h" #include "object.h" #include "menu.h" #include "physics.h" #include "dxxerror.h" #include "joy.h" #include "iff.h" #include "pcx.h" #include "timer.h" #include "render.h" #include "laser.h" #include "screens.h" #include "textures.h" #include "slew.h" #include "gauges.h" #include "texmap.h" #include "3d.h" #include "effects.h" #include "gameseg.h" #include "wall.h" #include "ai.h" #include "rbaudio.h" #include "digi.h" #include "u_mem.h" #include "palette.h" #include "morph.h" #include "lighting.h" #include "newdemo.h" #include "weapon.h" #include "sounds.h" #include "args.h" #include "gameseq.h" #include "automap.h" #include "text.h" #include "powerup.h" #include "songs.h" #include "newmenu.h" #include "gamefont.h" #include "endlevel.h" #include "config.h" #include "kconfig.h" #include "mouse.h" #include "titles.h" #include "gr.h" #include "playsave.h" #include "scores.h" #include "multi.h" #include "cntrlcen.h" #include "fuelcen.h" #include "pcx.h" #include "state.h" #include "piggy.h" #include "multibot.h" #include "ai.h" #include "rbaudio.h" #include "switch.h" #include "window.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif #include // Global Variables ----------------------------------------------------------- int Debug_spew; // External Variables --------------------------------------------------------- extern char WaitForRefuseAnswer,RefuseThisPlayer,RefuseTeam; #ifndef NDEBUG extern int Mark_count; #endif extern int Global_missile_firing_count; extern int *Toggle_var; extern fix Show_view_text_timer; // Function prototypes -------------------------------------------------------- extern void CyclePrimary(); extern void CycleSecondary(); extern int allowed_to_fire_missile(void); extern int allowed_to_fire_flare(void); extern void check_rear_view(void); extern int create_special_path(void); extern void move_player_2_segment(segment *seg, int side); extern void newdemo_strip_frames(char *, int); extern void toggle_cockpit(void); extern void dump_used_textures_all(); int FinalCheats(int key); #ifndef RELEASE void do_cheat_menu(void); #endif int HandleGameKey(int key); int HandleSystemKey(int key); int HandleTestKey(int key); void advance_sound(void); void play_test_sound(void); #define key_isfunc(k) (((k&0xff)>=KEY_F1 && (k&0xff)<=KEY_F10) || (k&0xff)==KEY_F11 || (k&0xff)==KEY_F12) void update_vcr_state(); void do_weapon_n_item_stuff(void); // Control Functions fix64 newdemo_single_frame_time; void update_vcr_state(void) { if ((keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) && keyd_pressed[KEY_RIGHT] && d_tick_step) Newdemo_vcr_state = ND_STATE_FASTFORWARD; else if ((keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) && keyd_pressed[KEY_LEFT] && d_tick_step) Newdemo_vcr_state = ND_STATE_REWINDING; else if (!(keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL]) && keyd_pressed[KEY_RIGHT] && ((GameTime64 - newdemo_single_frame_time) >= F1_0) && d_tick_step) Newdemo_vcr_state = ND_STATE_ONEFRAMEFORWARD; else if (!(keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL]) && keyd_pressed[KEY_LEFT] && ((GameTime64 - newdemo_single_frame_time) >= F1_0) && d_tick_step) Newdemo_vcr_state = ND_STATE_ONEFRAMEBACKWARD; else if ((Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_REWINDING)) Newdemo_vcr_state = ND_STATE_PLAYBACK; } void do_weapon_n_item_stuff() { int i; if (Controls.fire_flare_count > 0) { Controls.fire_flare_count = 0; if (allowed_to_fire_flare()) Flare_create(ConsoleObject); } if (allowed_to_fire_missile() && Controls.fire_secondary_state) Global_missile_firing_count += Weapon_info[Secondary_weapon_to_weapon_info[Secondary_weapon]].fire_count; if (Global_missile_firing_count) { do_missile_firing(0); Global_missile_firing_count--; } if (Controls.cycle_primary_count > 0) { for (i=0;i 0) { for (i=0;i 0) { Controls.select_weapon_count--; do_weapon_select(Controls.select_weapon_count>4?Controls.select_weapon_count-5:Controls.select_weapon_count,Controls.select_weapon_count>4?1:0); Controls.select_weapon_count = 0; } if (Global_missile_firing_count < 0) Global_missile_firing_count = 0; // Drop proximity bombs. while (Controls.drop_bomb_count > 0) { do_missile_firing(1); Controls.drop_bomb_count--; } } extern void game_render_frame(); void format_time(char *str, int secs_int) { int h, m, s; h = secs_int/3600; s = secs_int%3600; m = s / 60; s = s % 60; sprintf(str, "%1d:%02d:%02d", h, m, s ); } extern int netplayerinfo_on; //Process selected keys until game unpaused int pause_handler(window *wind, d_event *event, char *msg) { int key; switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); break; case EVENT_KEY_COMMAND: key = event_key_get(event); switch (key) { case 0: break; case KEY_ESC: window_close(wind); return 1; case KEY_F1: show_help(); return 1; case KEY_PAUSE: window_close(wind); return 1; default: break; } break; case EVENT_IDLE: timer_delay2(50); break; case EVENT_WINDOW_DRAW: show_boxed_message(msg, 1); break; case EVENT_WINDOW_CLOSE: songs_resume(); d_free(msg); break; default: break; } return 0; } int do_game_pause() { char *msg; char total_time[9],level_time[9]; #ifdef NETWORK if (Game_mode & GM_MULTI) { netplayerinfo_on= !netplayerinfo_on; return(KEY_PAUSE); } #endif MALLOC(msg, char, 1024); if (!msg) return 0; songs_pause(); format_time(total_time, f2i(Players[Player_num].time_total) + Players[Player_num].hours_total*3600); format_time(level_time, f2i(Players[Player_num].time_level) + Players[Player_num].hours_level*3600); if (Newdemo_state!=ND_STATE_PLAYBACK) snprintf(msg,1024,"PAUSE\n\nSkill level: %s\nHostages on board: %d\nTime on level: %s\nTotal time in game: %s",MENU_DIFFICULTY_TEXT(Difficulty_level),Players[Player_num].hostages_on_board,level_time,total_time); else snprintf(msg,1024,"PAUSE\n\nSkill level: %s\nHostages on board: %d\n",MENU_DIFFICULTY_TEXT(Difficulty_level),Players[Player_num].hostages_on_board); set_screen_mode(SCREEN_MENU); if (!window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))pause_handler, msg)) d_free(msg); return 0 /*key*/; // Keycode returning ripped out (kreatordxx) } int HandleEndlevelKey(int key) { switch (key) { case KEY_COMMAND+KEY_P: case KEY_PAUSE: do_game_pause(); return 1; case KEY_ESC: stop_endlevel_sequence(); last_drawn_cockpit=-1; return 1; } return 0; } int HandleDeathInput(d_event *event) { if (event->type == EVENT_KEY_COMMAND) { int key = event_key_get(event); if (Player_exploded && !key_isfunc(key) && key != KEY_PAUSE && key) Death_sequence_aborted = 1; //Any key but func or modifier aborts if (key == KEY_ESC) if (ConsoleObject->flags & OF_EXPLODING) Death_sequence_aborted = 1; } if (Player_exploded && (event->type == EVENT_JOYSTICK_BUTTON_UP || event->type == EVENT_MOUSE_BUTTON_UP)) Death_sequence_aborted = 1; if (Death_sequence_aborted) { game_flush_inputs(); return 1; } return 0; } int HandleDemoKey(int key) { switch (key) { KEY_MAC(case KEY_COMMAND+KEY_1:) case KEY_F1: show_newdemo_help(); break; KEY_MAC(case KEY_COMMAND+KEY_2:) case KEY_F2: do_options_menu(); break; KEY_MAC(case KEY_COMMAND+KEY_3:) case KEY_F3: toggle_cockpit(); break; KEY_MAC(case KEY_COMMAND+KEY_4:) case KEY_F4: Newdemo_show_percentage = !Newdemo_show_percentage; break; KEY_MAC(case KEY_COMMAND+KEY_7:) case KEY_F7: #ifdef NETWORK Show_kill_list = (Show_kill_list+1) % ((Newdemo_game_mode & GM_TEAM) ? 4 : 3); #endif break; case KEY_ESC: if (GameArg.SysAutoDemo) { int choice; choice = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_AUTODEMO ); if (choice == 0) GameArg.SysAutoDemo = 0; else break; } newdemo_stop_playback(); break; case KEY_UP: Newdemo_vcr_state = ND_STATE_PLAYBACK; break; case KEY_DOWN: Newdemo_vcr_state = ND_STATE_PAUSED; break; case KEY_LEFT: newdemo_single_frame_time = GameTime64; Newdemo_vcr_state = ND_STATE_ONEFRAMEBACKWARD; break; case KEY_RIGHT: newdemo_single_frame_time = GameTime64; Newdemo_vcr_state = ND_STATE_ONEFRAMEFORWARD; break; case KEY_CTRLED + KEY_RIGHT: newdemo_goto_end(0); break; case KEY_CTRLED + KEY_LEFT: newdemo_goto_beginning(); break; KEY_MAC(case KEY_COMMAND+KEY_P:) case KEY_PAUSE: do_game_pause(); break; #ifdef macintosh case KEY_COMMAND + KEY_SHIFTED + KEY_3: #endif case KEY_PRINT_SCREEN: { if (PlayerCfg.PRShot) { gr_set_current_canvas(NULL); render_frame(0); gr_set_curfont(MEDIUM2_FONT); gr_printf(SWIDTH-FSPACX(92),SHEIGHT-LINE_SPACING,"DXX-Rebirth\n"); gr_flip(); save_screen_shot(0); } else { int old_state; old_state = Newdemo_show_percentage; Newdemo_show_percentage = 0; game_render_frame_mono(0); if (GameArg.DbgUseDoubleBuffer) gr_flip(); save_screen_shot(0); Newdemo_show_percentage = old_state; } break; } #ifndef NDEBUG case KEY_DEBUGGED + KEY_I: Newdemo_do_interpolate = !Newdemo_do_interpolate; HUD_init_message(HM_DEFAULT, "Demo playback interpolation %s", Newdemo_do_interpolate?"ON":"OFF"); break; case KEY_DEBUGGED + KEY_K: { int how_many, c; char filename[FILENAME_LEN], num[16]; newmenu_item m[6]; filename[0] = '\0'; m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "output file name"; m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename; c = newmenu_do( NULL, NULL, 2, m, NULL, NULL ); if (c == -2) break; strcat(filename, DEMO_EXT); num[0] = '\0'; m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "strip how many bytes"; m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 16; m[1].text = num; c = newmenu_do( NULL, NULL, 2, m, NULL, NULL ); if (c == -2) break; how_many = atoi(num); if (how_many <= 0) break; newdemo_strip_frames(filename, how_many); break; } #endif default: return 0; } return 1; } //this is for system-level keys, such as help, etc. //returns 1 if screen changed int HandleSystemKey(int key) { if (!Player_is_dead) switch (key) { case KEY_ESC: { int choice; choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME ); if (choice == 0) window_close(Game_wind); return 1; } } switch (key) { KEY_MAC( case KEY_COMMAND+KEY_P: ) case KEY_PAUSE: do_game_pause(); break; #ifdef macintosh case KEY_COMMAND + KEY_SHIFTED + KEY_3: #endif case KEY_PRINT_SCREEN: { if (PlayerCfg.PRShot) { gr_set_current_canvas(NULL); render_frame(0); gr_set_curfont(MEDIUM2_FONT); gr_printf(SWIDTH-FSPACX(92),SHEIGHT-LINE_SPACING,"DXX-Rebirth\n"); gr_flip(); save_screen_shot(0); } else { game_render_frame_mono(0); if(GameArg.DbgUseDoubleBuffer) gr_flip(); save_screen_shot(0); } break; } KEY_MAC(case KEY_COMMAND+KEY_1:) case KEY_F1: if (Game_mode & GM_MULTI) show_netgame_help(); else show_help(); break; KEY_MAC(case KEY_COMMAND+KEY_2:) case KEY_F2: { do_options_menu(); break; } KEY_MAC(case KEY_COMMAND+KEY_3:) case KEY_F3: if (!Player_is_dead) toggle_cockpit(); break; KEY_MAC(case KEY_COMMAND+KEY_5:) case KEY_F5: if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_stop_recording(); else if ( Newdemo_state == ND_STATE_NORMAL ) newdemo_start_recording(); break; #ifdef NETWORK KEY_MAC(case KEY_COMMAND+KEY_ALTED+KEY_4:) case KEY_ALTED + KEY_F4: Show_reticle_name = (Show_reticle_name+1)%2; break; KEY_MAC(case KEY_COMMAND+KEY_7:) case KEY_F7: Show_kill_list = (Show_kill_list+1) % ((Game_mode & GM_TEAM) ? 4 : 3); if (Game_mode & GM_MULTI) multi_sort_kill_list(); break; KEY_MAC(case KEY_COMMAND+KEY_8:) case KEY_F8: multi_send_message_start(); break; case KEY_F9: case KEY_F10: case KEY_F11: case KEY_F12: multi_send_macro(key); break; // send taunt macros #if defined(__APPLE__) || defined(macintosh) case KEY_9 + KEY_COMMAND: multi_send_macro(KEY_F9); break; case KEY_0 + KEY_COMMAND: multi_send_macro(KEY_F10); break; case KEY_1 + KEY_COMMAND + KEY_CTRLED: multi_send_macro(KEY_F11); break; case KEY_2 + KEY_COMMAND + KEY_CTRLED: multi_send_macro(KEY_F12); break; #endif case KEY_SHIFTED + KEY_F9: case KEY_SHIFTED + KEY_F10: case KEY_SHIFTED + KEY_F11: case KEY_SHIFTED + KEY_F12: multi_define_macro(key); break; // redefine taunt macros #if defined(__APPLE__) || defined(macintosh) case KEY_9 + KEY_SHIFTED + KEY_COMMAND: multi_define_macro(KEY_F9); break; case KEY_0 + KEY_SHIFTED + KEY_COMMAND: multi_define_macro(KEY_F10); break; case KEY_1 + KEY_SHIFTED + KEY_COMMAND + KEY_CTRLED: multi_define_macro(KEY_F11); break; case KEY_2 + KEY_SHIFTED + KEY_COMMAND + KEY_CTRLED: multi_define_macro(KEY_F12); break; #endif #endif KEY_MAC(case KEY_COMMAND+KEY_SHIFTED+KEY_S:) KEY_MAC(case KEY_COMMAND+KEY_ALTED+KEY_2:) case KEY_ALTED+KEY_F2: if (!Player_is_dead) state_save_all( 0 ); break; KEY_MAC(case KEY_COMMAND+KEY_S:) case KEY_ALTED+KEY_F1: if (!Player_is_dead) state_save_all(1); break; KEY_MAC(case KEY_COMMAND+KEY_O:) KEY_MAC(case KEY_COMMAND+KEY_ALTED+KEY_3:) case KEY_ALTED+KEY_F3: if (!((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP))) state_restore_all(1); break; /* * Jukebox hotkeys -- MD2211, 2007 * Now for all music * ============================================== */ case KEY_ALTED + KEY_SHIFTED + KEY_F9: KEY_MAC(case KEY_COMMAND+KEY_E:) if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) { songs_stop_all(); RBAEjectDisk(); } break; case KEY_ALTED + KEY_SHIFTED + KEY_F10: KEY_MAC(case KEY_COMMAND+KEY_UP:) KEY_MAC(case KEY_COMMAND+KEY_DOWN:) songs_pause_resume(); break; case KEY_MINUS + KEY_ALTED: case KEY_ALTED + KEY_SHIFTED + KEY_F11: KEY_MAC(case KEY_COMMAND+KEY_LEFT:) songs_play_level_song( Current_level_num, -1 ); break; case KEY_EQUAL + KEY_ALTED: case KEY_ALTED + KEY_SHIFTED + KEY_F12: KEY_MAC(case KEY_COMMAND+KEY_RIGHT:) songs_play_level_song( Current_level_num, 1 ); break; default: return 0; break; } return 1; } int HandleGameKey(int key) { switch (key) { case KEY_ALTED+KEY_F7: KEY_MAC(case KEY_COMMAND+KEY_ALTED+KEY_7:) PlayerCfg.HudMode=(PlayerCfg.HudMode+1)%GAUGE_HUD_NUMMODES; write_player_file(); switch (PlayerCfg.HudMode) { case 0: HUD_init_message_literal(HM_DEFAULT, "Standard HUD"); break; case 1: HUD_init_message_literal(HM_DEFAULT, "Alternative HUD #1"); break; case 2: HUD_init_message_literal(HM_DEFAULT, "Alternative HUD #2"); break; case 3: HUD_init_message_literal(HM_DEFAULT, "No HUD"); break; } break; #ifdef NETWORK KEY_MAC(case KEY_COMMAND+KEY_6:) case KEY_F6: if (Netgame.RefusePlayers && WaitForRefuseAnswer) { RefuseThisPlayer=1; HUD_init_message_literal(HM_MULTI, "Player accepted!"); } break; case KEY_ALTED + KEY_1: if (Netgame.RefusePlayers && WaitForRefuseAnswer && (Game_mode & GM_TEAM)) { RefuseThisPlayer=1; HUD_init_message_literal(HM_MULTI, "Player accepted!"); RefuseTeam=1; game_flush_inputs(); } break; case KEY_ALTED + KEY_2: if (Netgame.RefusePlayers && WaitForRefuseAnswer && (Game_mode & GM_TEAM)) { RefuseThisPlayer=1; HUD_init_message_literal(HM_MULTI, "Player accepted!"); RefuseTeam=2; game_flush_inputs(); } break; #endif default: return 0; break; } //switch (key) return 1; } // -------------------------------------------------------------------------- // Detonate reactor. // Award player all powerups in mine. // Place player just outside exit. // Kill all bots in mine. // Yippee!! void kill_and_so_forth(void) { int i, j; HUD_init_message_literal(HM_DEFAULT, "Killing, awarding, etc.!"); for (i=0; i<=Highest_object_index; i++) { switch (Objects[i].type) { case OBJ_ROBOT: Objects[i].flags |= OF_EXPLODING|OF_SHOULD_BE_DEAD; break; case OBJ_POWERUP: do_powerup(&Objects[i]); break; } } do_controlcen_destroyed_stuff(NULL); for (i=0; ipos, &Segments[Walls[j].segnum]); obj_relink(ConsoleObject-Objects,Walls[j].segnum); goto kasf_done; } } } } kasf_done: ; } #ifndef RELEASE int HandleTestKey(int key) { switch (key) { #ifdef SHOW_EXIT_PATH case KEY_DEBUGGED+KEY_1: create_special_path(); break; #endif case KEY_DEBUGGED+KEY_Y: do_controlcen_destroyed_stuff(NULL); break; case KEY_BACKSP: case KEY_CTRLED+KEY_BACKSP: case KEY_ALTED+KEY_BACKSP: case KEY_SHIFTED+KEY_BACKSP: case KEY_SHIFTED+KEY_ALTED+KEY_BACKSP: case KEY_CTRLED+KEY_ALTED+KEY_BACKSP: case KEY_SHIFTED+KEY_CTRLED+KEY_BACKSP: case KEY_SHIFTED+KEY_CTRLED+KEY_ALTED+KEY_BACKSP: Int3(); break; case KEY_DEBUGGED+KEY_S: digi_reset(); break; case KEY_DEBUGGED+KEY_P: if (Game_suspended & SUSP_ROBOTS) Game_suspended &= ~SUSP_ROBOTS; //robots move else Game_suspended |= SUSP_ROBOTS; //robots don't move break; case KEY_DEBUGGED+KEY_K: Players[Player_num].shields = 1; break; // a virtual kill case KEY_DEBUGGED+KEY_SHIFTED + KEY_K: Players[Player_num].shields = -1; break; // an actual kill case KEY_DEBUGGED+KEY_X: Players[Player_num].lives++; break; // Extra life cheat key. case KEY_DEBUGGED+KEY_H: if (Player_is_dead) return 0; Players[Player_num].flags ^= PLAYER_FLAGS_CLOAKED; if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_cloak(); #endif ai_do_cloak_stuff(); Players[Player_num].cloak_time = GameTime64; } break; case KEY_DEBUGGED+KEY_R: cheats.robotfiringsuspended = !cheats.robotfiringsuspended; break; #ifdef EDITOR //editor-specific functions case KEY_E + KEY_DEBUGGED: window_set_visible(Game_wind, 0); // don't let the game do anything while we set the editor up init_editor(); window_close(Game_wind); break; case KEY_C + KEY_SHIFTED + KEY_DEBUGGED: if (!Player_is_dead && !( Game_mode & GM_MULTI )) move_player_2_segment(Cursegp,Curside); break; //move eye to curseg case KEY_DEBUGGED+KEY_W: draw_world_from_game(); break; #endif //#ifdef EDITOR case KEY_DEBUGGED+KEY_LAPOSTRO: Show_view_text_timer = 0x30000; object_goto_next_viewer(); break; case KEY_DEBUGGED+KEY_SHIFTED+KEY_LAPOSTRO: Viewer=ConsoleObject; break; case KEY_DEBUGGED+KEY_O: toggle_outline_mode(); break; case KEY_DEBUGGED+KEY_T: *Toggle_var = !*Toggle_var; break; case KEY_DEBUGGED + KEY_L: if (++Lighting_on >= 2) Lighting_on = 0; break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_L: Beam_brightness=0x38000-Beam_brightness; break; case KEY_PAD5: slew_stop(); break; #ifndef NDEBUG case KEY_DEBUGGED + KEY_F11: play_test_sound(); break; case KEY_DEBUGGED + KEY_SHIFTED+KEY_F11: advance_sound(); play_test_sound(); break; #endif case KEY_DEBUGGED + KEY_M: Debug_spew = !Debug_spew; if (Debug_spew) { HUD_init_message_literal(HM_DEFAULT, "Debug Spew: ON" ); } else { HUD_init_message_literal(HM_DEFAULT, "Debug Spew: OFF" ); } break; case KEY_DEBUGGED + KEY_C: do_cheat_menu(); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_A: do_megawow_powerup(10); break; case KEY_DEBUGGED + KEY_A: { do_megawow_powerup(200); break; } case KEY_DEBUGGED+KEY_SPACEBAR: //KEY_F7: // Toggle physics flying slew_stop(); game_flush_inputs(); if ( ConsoleObject->control_type != CT_FLYING ) { fly_init(ConsoleObject); Game_suspended &= ~SUSP_ROBOTS; //robots move } else { slew_init(ConsoleObject); //start player slewing Game_suspended |= SUSP_ROBOTS; //robots don't move } break; case KEY_DEBUGGED+KEY_COMMA: Render_zoom = fixmul(Render_zoom,62259); break; case KEY_DEBUGGED+KEY_PERIOD: Render_zoom = fixmul(Render_zoom,68985); break; #ifndef NDEBUG case KEY_DEBUGGED+KEY_D: if ((GameArg.DbgUseDoubleBuffer = !GameArg.DbgUseDoubleBuffer)!=0) init_cockpit(); break; #endif #ifdef EDITOR case KEY_DEBUGGED+KEY_Q: stop_time(); dump_used_textures_all(); start_time(); break; #endif case KEY_DEBUGGED+KEY_B: { newmenu_item m; char text[FILENAME_LEN]=""; int item; m.type=NM_TYPE_INPUT; m.text_len = FILENAME_LEN; m.text = text; item = newmenu_do( NULL, "Briefing to play?", 1, &m, NULL, NULL ); if (item != -1) { do_briefing_screens(text,1); } break; } case KEY_DEBUGGED+KEY_SHIFTED+KEY_B: if (Player_is_dead) return 0; kill_and_so_forth(); break; case KEY_DEBUGGED+KEY_G: GameTime64 = (0x7fffffffffffffffLL) - (F1_0*10); HUD_init_message(HM_DEFAULT, "GameTime %li - Reset in 10 seconds!", GameTime64); break; default: return 0; break; } return 1; } #endif //#ifndef RELEASE // Cheat functions ------------------------------------------------------------ #define CHEAT_MAX_LEN 15 #define NUM_CHEATS 16 typedef struct cheat_code { char *string; int *stateptr; } __pack__ cheat_code; cheat_code cheat_codes[NUM_CHEATS] = { { "gabbagabbahey", &cheats.enabled }, { "scourge", &cheats.wowie }, { "bigred", &cheats.wowie2 }, { "mitzi", &cheats.allkeys }, { "racerx", &cheats.invul }, { "guile", &cheats.cloak }, { "twilight", &cheats.shields }, { "poboys", &cheats.killreactor }, { "flash", &cheats.exitpath }, { "farmerjoe", &cheats.levelwarp }, { "bruin", &cheats.extralife }, { "astral", &cheats.ghostphysics }, { "porgys", &cheats.rapidfire }, { "buggin", &cheats.turbo }, { "ahimsa", &cheats.robotfiringsuspended }, { "bittersweet", &cheats.acid }, }; int FinalCheats(int key) { static char cheat_buffer[CHEAT_MAX_LEN] = "AAAAAAAAAAAAAAA"; int i = 0, gotcha = 0; if (Game_mode & GM_MULTI) return 0; for (i = 1; i < CHEAT_MAX_LEN; i++) cheat_buffer[i-1] = cheat_buffer[i]; cheat_buffer[CHEAT_MAX_LEN-1] = key_ascii(); for (i = 0; i < NUM_CHEATS; i++) { int cheatlen = strlen(cheat_codes[i].string); Assert(cheatlen <= CHEAT_MAX_LEN); if (d_strnicmp(cheat_codes[i].string, cheat_buffer+CHEAT_MAX_LEN-cheatlen, cheatlen)==0) { if (!cheats.enabled && *cheat_codes[i].stateptr != cheats.enabled) break; if (!cheats.enabled) HUD_init_message(HM_DEFAULT, TXT_CHEATS_ENABLED); *cheat_codes[i].stateptr = !*cheat_codes[i].stateptr; cheats.enabled = 1; digi_play_sample( SOUND_CHEATER, F1_0); Players[Player_num].score = 0; gotcha = i; break; } } if (!gotcha) return 0; if (cheat_codes[gotcha].stateptr == &cheats.wowie) { HUD_init_message_literal(HM_DEFAULT, TXT_WOWIE_ZOWIE); Players[Player_num].primary_weapon_flags |= 0xff ^ (HAS_PLASMA_FLAG | HAS_FUSION_FLAG); Players[Player_num].secondary_weapon_flags |= 0xff ^ (HAS_SMART_FLAG | HAS_MEGA_FLAG); for (i=0; i<3; i++) Players[Player_num].primary_ammo[i] = Primary_ammo_max[i]; for (i=0; i<3; i++) Players[Player_num].secondary_ammo[i] = Secondary_ammo_max[i]; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_laser_level(Players[Player_num].laser_level, MAX_LASER_LEVEL); Players[Player_num].energy = MAX_ENERGY; Players[Player_num].laser_level = MAX_LASER_LEVEL; Players[Player_num].flags |= PLAYER_FLAGS_QUAD_LASERS; update_laser_weapon_info(); } if (cheat_codes[gotcha].stateptr == &cheats.wowie2) { HUD_init_message(HM_DEFAULT, "SUPER %s",TXT_WOWIE_ZOWIE); Players[Player_num].primary_weapon_flags = 0xff; Players[Player_num].secondary_weapon_flags = 0xff; for (i=0; i=0 && new_level_num<=Last_level) { window_set_visible(Game_wind, 0); StartNewLevel(new_level_num); window_set_visible(Game_wind, 1); } } } if (cheat_codes[gotcha].stateptr == &cheats.ghostphysics) { HUD_init_message(HM_DEFAULT, "%s %s!", "Ghosty mode", cheats.ghostphysics?TXT_ON:TXT_OFF); } if (cheat_codes[gotcha].stateptr == &cheats.rapidfire) { do_megawow_powerup(200); } if (cheat_codes[gotcha].stateptr == &cheats.turbo) { HUD_init_message(HM_DEFAULT, "%s %s!", "Turbo mode", cheats.turbo?TXT_ON:TXT_OFF); } if (cheat_codes[gotcha].stateptr == &cheats.robotfiringsuspended) { HUD_init_message(HM_DEFAULT, "Robot firing %s!", cheats.robotfiringsuspended?TXT_OFF:TXT_ON); } if (cheat_codes[gotcha].stateptr == &cheats.acid) { HUD_init_message_literal(HM_DEFAULT, cheats.acid?"Going up!":"Coming down!"); } return 1; } // Internal Cheat Menu #ifndef RELEASE void do_cheat_menu() { int mmn; newmenu_item mm[16]; char score_text[21]; sprintf( score_text, "%d", Players[Player_num].score ); mm[0].type=NM_TYPE_CHECK; mm[0].value=Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE; mm[0].text="Invulnerability"; mm[1].type=NM_TYPE_CHECK; mm[1].value=Players[Player_num].flags & PLAYER_FLAGS_CLOAKED; mm[1].text="Cloaked"; mm[2].type=NM_TYPE_CHECK; mm[2].value=0; mm[2].text="All keys"; mm[3].type=NM_TYPE_NUMBER; mm[3].value=f2i(Players[Player_num].energy); mm[3].text="% Energy"; mm[3].min_value=0; mm[3].max_value=200; mm[4].type=NM_TYPE_NUMBER; mm[4].value=f2i(Players[Player_num].shields); mm[4].text="% Shields"; mm[4].min_value=0; mm[4].max_value=200; mm[5].type=NM_TYPE_TEXT; mm[5].text = "Score:"; mm[6].type=NM_TYPE_INPUT; mm[6].text_len = 10; mm[6].text = score_text; mm[7].type=NM_TYPE_RADIO; mm[7].value=(Players[Player_num].laser_level==0); mm[7].group=0; mm[7].text="Laser level 1"; mm[8].type=NM_TYPE_RADIO; mm[8].value=(Players[Player_num].laser_level==1); mm[8].group=0; mm[8].text="Laser level 2"; mm[9].type=NM_TYPE_RADIO; mm[9].value=(Players[Player_num].laser_level==2); mm[9].group=0; mm[9].text="Laser level 3"; mm[10].type=NM_TYPE_RADIO; mm[10].value=(Players[Player_num].laser_level==3); mm[10].group=0; mm[10].text="Laser level 4"; mm[11].type=NM_TYPE_NUMBER; mm[11].value=Players[Player_num].secondary_ammo[CONCUSSION_INDEX]; mm[11].text="Missiles"; mm[11].min_value=0; mm[11].max_value=200; mmn = newmenu_do("Wimp Menu",NULL,12, mm, NULL, NULL ); if (mmn > -1 ) { if ( mm[0].value ) { Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE; Players[Player_num].invulnerable_time = GameTime64+i2f(1000); } else Players[Player_num].flags &= ~PLAYER_FLAGS_INVULNERABLE; if ( mm[1].value ) { Players[Player_num].flags |= PLAYER_FLAGS_CLOAKED; #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_cloak(); #endif ai_do_cloak_stuff(); Players[Player_num].cloak_time = GameTime64; } else Players[Player_num].flags &= ~PLAYER_FLAGS_CLOAKED; if (mm[2].value) Players[Player_num].flags |= PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY; Players[Player_num].energy=i2f(mm[3].value); Players[Player_num].shields=i2f(mm[4].value); Players[Player_num].score = atoi(mm[6].text); if (mm[7].value) Players[Player_num].laser_level=0; if (mm[8].value) Players[Player_num].laser_level=1; if (mm[9].value) Players[Player_num].laser_level=2; if (mm[10].value) Players[Player_num].laser_level=3; Players[Player_num].secondary_ammo[CONCUSSION_INDEX] = mm[11].value; init_gauges(); } } #endif // Testing functions ---------------------------------------------------------- #ifndef NDEBUG // Sounds for testing int test_sound_num = 0; int sound_nums[] = {10,11,20,21,30,31,32,33,40,41,50,51,60,61,62,70,80,81,82,83,90,91}; #define N_TEST_SOUNDS (sizeof(sound_nums) / sizeof(*sound_nums)) void advance_sound() { if (++test_sound_num == N_TEST_SOUNDS) test_sound_num=0; } int Test_sound = 251; void play_test_sound() { // -- digi_play_sample(sound_nums[test_sound_num], F1_0); digi_play_sample(Test_sound, F1_0); } #endif //ifndef NDEBUG int ReadControls(d_event *event) { int key; static ubyte exploding_flag=0; Player_fired_laser_this_frame=-1; if (Player_exploded) { if (exploding_flag==0) { exploding_flag = 1; // When player starts exploding, clear all input devices... game_flush_inputs(); } } else { exploding_flag=0; } if (Player_is_dead && !( (Game_mode & GM_MULTI) && (multi_sending_message[Player_num] || multi_defining_message) )) if (HandleDeathInput(event)) return 1; if (Newdemo_state == ND_STATE_PLAYBACK) update_vcr_state(); if (event->type == EVENT_KEY_COMMAND) { key = event_key_get(event); #ifdef NETWORK if ( (Game_mode & GM_MULTI) && (multi_sending_message[Player_num] || multi_defining_message) ) { return multi_message_input_sub(key); } #endif #ifndef RELEASE #ifdef NETWORK if ((key&KEY_DEBUGGED)&&(Game_mode&GM_MULTI)) { Network_message_reciever = 100; // Send to everyone... sprintf( Network_message, "%s %s", TXT_I_AM_A, TXT_CHEATER); } #endif #endif if (Endlevel_sequence) { if (HandleEndlevelKey(key)) return 1; } else if (Newdemo_state == ND_STATE_PLAYBACK ) { if (HandleDemoKey(key)) return 1; } else { if (FinalCheats(key)) return 1; if (HandleSystemKey(key)) return 1; if (HandleGameKey(key)) return 1; } #ifndef RELEASE if (HandleTestKey(key)) return 1; #endif if (call_default_handler(event)) return 1; } if (!Endlevel_sequence && !Player_is_dead && (Newdemo_state != ND_STATE_PLAYBACK)) { kconfig_read_controls(event, 0); check_rear_view(); // If automap key pressed, enable automap unless you are in network mode, control center destroyed and < 10 seconds left if ( Controls.automap_count > 0 ) { Controls.automap_count = 0; if (!((Game_mode & GM_MULTI) && Control_center_destroyed && (Countdown_seconds_left < 10))) { do_automap(0); return 1; } } do_weapon_n_item_stuff(); } return 0; } dxx-rebirth-0.58.1-d1x/main/gamefont.c000066400000000000000000000112511217717257200174420ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Fonts for the game. * */ #include #include #include "gr.h" #include "dxxerror.h" #include #include "strutil.h" #include "args.h" #include "gamefont.h" #include "mission.h" #include "config.h" static const char Gamefont_filenames_l[][16] = { "font1-1.fnt", // Font 0 "font2-1.fnt", // Font 1 "font2-2.fnt", // Font 2 "font2-3.fnt", // Font 3 "font3-1.fnt" // Font 4 }; static const char Gamefont_filenames_h[][16] = { "font1-1h.fnt", // Font 0 "font2-1h.fnt", // Font 1 "font2-2h.fnt", // Font 2 "font2-3h.fnt", // Font 3 "font3-1h.fnt" // Font 4 }; grs_font *Gamefonts[MAX_FONTS]; int Gamefont_installed=0; float FNTScaleX = 1, FNTScaleY = 1; //code to allow variable GAME_FONT, added 10/7/99 Matt Mueller - updated 11/18/99 to handle all fonts, not just GFONT_SMALL // take scry into account? how/when? typedef struct _a_gamefont_conf{ int x; int y; union{ char name[64];//hrm. grs_font *ptr; } f; }a_gamefont_conf; typedef struct _gamefont_conf{ a_gamefont_conf font[10]; int num,cur; }gamefont_conf; gamefont_conf font_conf[MAX_FONTS]; const char *gamefont_curfontname(int gf){ if (font_conf[gf].cur<0) return Gamefont_filenames_l[gf]; else return font_conf[gf].font[font_conf[gf].cur].f.name; } static void gamefont_unloadfont(int gf) { if (Gamefonts[gf]){ font_conf[gf].cur=-1; gr_close_font(Gamefonts[gf]); Gamefonts[gf]=NULL; } } static void gamefont_loadfont(int gf,int fi) { if (PHYSFSX_exists(font_conf[gf].font[fi].f.name,1)){ gamefont_unloadfont(gf); Gamefonts[gf]=gr_init_font(font_conf[gf].font[fi].f.name); }else { if (Gamefonts[gf]==NULL){ Gamefonts[gf]=gr_init_font(Gamefont_filenames_l[gf]); font_conf[gf].cur=-1; } return; } font_conf[gf].cur=fi; } void gamefont_choose_game_font(int scrx,int scry){ int gf,i,close=-1,m=-1; if (!Gamefont_installed) return; for (gf=0;gf=font_conf[gf].font[i].x && close=font_conf[gf].font[i].y && closesc_canvas.cv_bitmap.bm_w,grd_curscreen->sc_canvas.cv_bitmap.bm_h); } void gamefont_close() { int i; if (!Gamefont_installed) return; Gamefont_installed = 0; for (i=0; ift_w/7)))) #define FSPACY(y) ((float)((y)*(FNTScaleY*(GAME_FONT->ft_h/5)))) #define LINE_SPACING ((float)(FNTScaleY*(grd_curcanv->cv_font->ft_h+(GAME_FONT->ft_h/5)))) extern grs_font *Gamefonts[MAX_FONTS]; void gamefont_init(); void gamefont_close(); void gamefont_choose_game_font(int scrx,int scry); #endif /* _GAMEFONT_H */ dxx-rebirth-0.58.1-d1x/main/gamemine.c000066400000000000000000000466541217717257200174430ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for loading mines in the game * */ #include #include #include #include #include "inferno.h" #include "segment.h" #include "textures.h" #include "wall.h" #include "object.h" #include "gamemine.h" #include "gamesave.h" #include "dxxerror.h" #include "gameseg.h" #include "switch.h" #include "game.h" #include "newmenu.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif #include "fuelcen.h" #include "hash.h" #include "key.h" #include "piggy.h" #define REMOVE_EXT(s) (*(strchr( (s), '.' ))='\0') int CreateDefaultNewSegment(); int load_mine_data_compiled_new(PHYSFS_file *LoadFile); #ifdef EDITOR static char old_tmap_list[MAX_TEXTURES][13]; short tmap_xlate_table[MAX_TEXTURES]; static short tmap_times_used[MAX_TEXTURES]; struct mtfi mine_top_fileinfo; // Should be same as first two fields below... struct mfi mine_fileinfo; struct mh mine_header; struct me mine_editor; // ----------------------------------------------------------------------------- //loads from an already-open file // returns 0=everything ok, 1=old version, -1=error int load_mine_data(PHYSFS_file *LoadFile) { int i, j; short tmap_xlate; int translate; char *temptr; int mine_start = PHYSFS_tell(LoadFile); fuelcen_reset(); for (i=0; i -1 ) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.header_offset, SEEK_SET )) Error( "Error seeking to header_offset in gamemine.c" ); if (PHYSFS_read( LoadFile, &mine_header, mine_fileinfo.header_size, 1 )!=1) Error( "Error reading mine_header in gamemine.c" ); } //===================== READ EDITOR INFO ========================== // Set default values mine_editor.current_seg = 0; mine_editor.newsegment_offset = -1; // To be written mine_editor.newsegment_size = sizeof(segment); mine_editor.Curside = 0; mine_editor.Markedsegp = -1; mine_editor.Markedside = 0; if (mine_fileinfo.editor_offset > -1 ) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.editor_offset, SEEK_SET )) Error( "Error seeking to editor_offset in gamemine.c" ); if (PHYSFS_read( LoadFile, &mine_editor, mine_fileinfo.editor_size, 1 )!=1) Error( "Error reading mine_editor in gamemine.c" ); } //===================== READ TEXTURE INFO ========================== if ( (mine_fileinfo.texture_offset > -1) && (mine_fileinfo.texture_howmany > 0)) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.texture_offset, SEEK_SET )) Error( "Error seeking to texture_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.texture_howmany; i++ ) { if (PHYSFS_read( LoadFile, &old_tmap_list[i], mine_fileinfo.texture_sizeof, 1 )!=1) Error( "Error reading old_tmap_list[i] in gamemine.c" ); } } //=============== GENERATE TEXTURE TRANSLATION TABLE =============== translate = 0; Assert (NumTextures < MAX_TEXTURES); { hashtable ht; hashtable_init( &ht, NumTextures ); // Remove all the file extensions in the textures list for (i=0;i= 0) tmap_times_used[tmap_xlate_table[j]]++; } { int count = 0; for (i=0; i MAX_VERTICES ) { mine_fileinfo.vertex_howmany = MAX_VERTICES; } if ( (mine_fileinfo.vertex_offset > -1) && (mine_fileinfo.vertex_howmany > 0)) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.vertex_offset, SEEK_SET )) Error( "Error seeking to vertex_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.vertex_howmany; i++ ) { // Set the default values for this vertex Vertices[i].x = 1; Vertices[i].y = 1; Vertices[i].z = 1; if (PHYSFS_read( LoadFile, &Vertices[i], mine_fileinfo.vertex_sizeof, 1 )!=1) Error( "Error reading Vertices[i] in gamemine.c" ); } } //==================== READ SEGMENT INFO =========================== // New check added to make sure we don't read in too many segments. if ( mine_fileinfo.segment_howmany > MAX_SEGMENTS ) { mine_fileinfo.segment_howmany = MAX_SEGMENTS; } // [commented out by mk on 11/20/94 (weren't we supposed to hit final in October?) because it looks redundant. I think I'll test it now...] fuelcen_reset(); if ( (mine_fileinfo.segment_offset > -1) && (mine_fileinfo.segment_howmany > 0)) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.segment_offset,SEEK_SET )) Error( "Error seeking to segment_offset in gamemine.c" ); Highest_segment_index = mine_fileinfo.segment_howmany-1; for (i=0; i< mine_fileinfo.segment_howmany; i++ ) { segment v16_seg; // Set the default values for this segment (clear to zero ) //memset( &Segments[i], 0, sizeof(segment) ); if (mine_top_fileinfo.fileinfo_version >= 16) { Assert(mine_fileinfo.segment_sizeof == sizeof(v16_seg)); if (PHYSFS_read( LoadFile, &v16_seg, mine_fileinfo.segment_sizeof, 1 )!=1) Error( "Error reading segments in gamemine.c" ); } else Error("Invalid mine version"); Segments[i] = v16_seg; Segments[i].objects = -1; #ifdef EDITOR Segments[i].group = -1; #endif if (mine_top_fileinfo.fileinfo_version < 15) { //used old uvl ranges int sn,uvln; for (sn=0;sn -1) { if (PHYSFSX_fseek( LoadFile, mine_editor.newsegment_offset,SEEK_SET )) Error( "Error seeking to newsegment_offset in gamemine.c" ); if (PHYSFS_read( LoadFile, &New_segment, mine_editor.newsegment_size,1 )!=1) Error( "Error reading new_segment in gamemine.c" ); } if ( (mine_fileinfo.newseg_verts_offset > -1) && (mine_fileinfo.newseg_verts_howmany > 0)) { if (PHYSFSX_fseek( LoadFile, mine_fileinfo.newseg_verts_offset, SEEK_SET )) Error( "Error seeking to newseg_verts_offset in gamemine.c" ); for (i=0; i< mine_fileinfo.newseg_verts_howmany; i++ ) { // Set the default values for this vertex Vertices[NEW_SEGMENT_VERTICES+i].x = 1; Vertices[NEW_SEGMENT_VERTICES+i].y = 1; Vertices[NEW_SEGMENT_VERTICES+i].z = 1; if (PHYSFS_read( LoadFile, &Vertices[NEW_SEGMENT_VERTICES+i], mine_fileinfo.newseg_verts_sizeof,1 )!=1) Error( "Error reading Vertices[NEW_SEGMENT_VERTICES+i] in gamemine.c" ); New_segment.verts[i] = NEW_SEGMENT_VERTICES+i; } } #endif //========================= UPDATE VARIABLES ====================== #ifdef EDITOR // Setting to Markedsegp to NULL ignores Curside and Markedside, which // we want to do when reading in an old file. Markedside = mine_editor.Markedside; Curside = mine_editor.Curside; for (i=0;i<10;i++) Groupside[i] = mine_editor.Groupside[i]; if ( mine_editor.current_seg != -1 ) Cursegp = mine_editor.current_seg + Segments; else Cursegp = NULL; if (mine_editor.Markedsegp != -1 ) Markedsegp = mine_editor.Markedsegp + Segments; else Markedsegp = NULL; num_groups = 0; current_group = -1; #endif Num_vertices = mine_fileinfo.vertex_howmany; Num_segments = mine_fileinfo.segment_howmany; Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; reset_objects(1); //one object, the player #ifdef EDITOR Highest_vertex_index = MAX_SEGMENT_VERTICES-1; Highest_segment_index = MAX_SEGMENTS-1; set_vertex_counts(); Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; warn_if_concave_segments(); #endif #ifdef EDITOR validate_segment_all(); #endif //create_local_segment_data(); //gamemine_find_textures(); if (mine_top_fileinfo.fileinfo_version < MINE_VERSION ) return 1; //old version else return 0; } #endif #define COMPILED_MINE_VERSION 0 int New_file_format_load = 1; void read_children(int segnum,ubyte bit_mask,PHYSFS_file *LoadFile) { int bit; for (bit=0; bitspecial = PHYSFSX_readByte(fp); if (s2->special >= MAX_CENTER_TYPES) s2->special = SEGMENT_IS_NOTHING; // remove goals etc. s2->matcen_num = PHYSFSX_readByte(fp); s2->value = PHYSFSX_readByte(fp); /*s2->s2_flags =*/ PHYSFSX_readByte(fp); // descent 2 ambient sound handling s2->static_light = PHYSFSX_readFix(fp); } int load_mine_data_compiled(PHYSFS_file *LoadFile) { int i, segnum, sidenum; ubyte compiled_version; short temp_short; ushort temp_ushort = 0; ubyte bit_mask; if (!strcmp(strchr(Gamesave_current_filename, '.'), ".sdl")) New_file_format_load = 0; // descent 1 shareware else New_file_format_load = 1; // For compiled levels, textures map to themselves, prevent tmap_override always being gray, // bug which Matt and John refused to acknowledge, so here is Mike, fixing it. // // Although in a cloud of arrogant glee, he forgot to ifdef it on EDITOR! // (Matt told me to write that!) #ifdef EDITOR for (i=0; i>5, write as short, l>>1 write as short) for (i=0; i<4; i++ ) { temp_short = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].u = ((fix)temp_short) << 5; temp_short = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].v = ((fix)temp_short) << 5; temp_ushort = PHYSFSX_readShort(LoadFile); Segments[segnum].sides[sidenum].uvls[i].l = ((fix)temp_ushort) << 1; //PHYSFS_read( LoadFile, &Segments[segnum].sides[sidenum].uvls[i].l, sizeof(fix), 1 ); } } else { Segments[segnum].sides[sidenum].tmap_num = 0; Segments[segnum].sides[sidenum].tmap_num2 = 0; for (i=0; i<4; i++ ) { Segments[segnum].sides[sidenum].uvls[i].u = 0; Segments[segnum].sides[sidenum].uvls[i].v = 0; Segments[segnum].sides[sidenum].uvls[i].l = 0; } } } } Highest_vertex_index = Num_vertices-1; Highest_segment_index = Num_segments-1; validate_segment_all(); // Fill in side type and normals. for (i=0; i 5) segment2_read(&Segments[i], LoadFile); fuelcen_activate( &Segments[i], Segments[i].special ); } reset_objects(1); //one object, the player return 0; } dxx-rebirth-0.58.1-d1x/main/gamemine.h000066400000000000000000000113151217717257200174320ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/gamemine.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:44:11 $ * * Header for gamemine.c * * $Log: gamemine.h,v $ * Revision 1.1.1.1 2006/03/17 19:44:11 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:23 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:28:50 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.15 1994/11/17 11:39:34 matt * Ripped out code to load old mines * * Revision 1.14 1994/10/19 16:46:40 matt * Made tmap overrides for robots remap texture numbers * * Revision 1.13 1994/09/23 22:14:37 matt * Took out obsolete structure fields * * Revision 1.12 1994/07/22 12:36:32 matt * Cleaned up editor/game interactions some more. * * Revision 1.11 1994/06/01 11:21:37 yuan * Added controlcentertriggers to the gamesave. * * Revision 1.10 1994/05/10 12:14:26 yuan * Game save/load... Demo levels 1-5 added... * High scores fixed... * * Revision 1.9 1994/05/04 18:25:05 yuan * Working on gamesave. * * Revision 1.8 1994/05/03 15:53:27 yuan * Readded structure field groups for backward compatibility... * * Revision 1.7 1994/05/03 11:36:26 yuan * Stabilizing gamesave stuff. * * Revision 1.6 1994/04/28 11:01:32 yuan * Added objects in structure. * * Revision 1.5 1994/04/06 18:30:03 john * Added Refueling segments. * * Revision 1.4 1994/03/17 18:06:53 yuan * Removed switch code... Now we just have Walls, Triggers, and Links... * * Revision 1.3 1994/03/01 18:12:24 yuan * Wallswitches, triggers, and more! * * Revision 1.2 1994/02/10 15:36:01 matt * Various changes to make editor compile out. * * Revision 1.1 1994/02/09 17:11:45 matt * Initial revision * * */ #ifndef _GAMEMINE_H #define _GAMEMINE_H #define MINE_VERSION 17 // Current version expected #define COMPATIBLE_VERSION 16 // Oldest version that can safely be loaded. struct mtfi { ushort fileinfo_signature; ushort fileinfo_version; int fileinfo_sizeof; }; // Should be same as first two fields below... struct mfi { ushort fileinfo_signature; ushort fileinfo_version; int fileinfo_sizeof; int header_offset; // Stuff common to game & editor int header_size; int editor_offset; // Editor specific stuff int editor_size; int segment_offset; int segment_howmany; int segment_sizeof; int newseg_verts_offset; int newseg_verts_howmany; int newseg_verts_sizeof; int group_offset; int group_howmany; int group_sizeof; int vertex_offset; int vertex_howmany; int vertex_sizeof; int texture_offset; int texture_howmany; int texture_sizeof; int walls_offset; int walls_howmany; int walls_sizeof; int triggers_offset; int triggers_howmany; int triggers_sizeof; int links_offset; int links_howmany; int links_sizeof; int object_offset; // Object info int object_howmany; int object_sizeof; int unused_offset; // was: doors_offset int unused_howmamy; // was: doors_howmany int unused_sizeof; // was: doors_sizeof }; struct mh { int num_vertices; int num_segments; }; struct me { int current_seg; int newsegment_offset; int newsegment_size; int Curside; int Markedsegp; int Markedside; int Groupsegp[10]; int Groupside[10]; int num_groups; int current_group; //int num_objects; }; extern struct mtfi mine_top_fileinfo; // Should be same as first two fields below... extern struct mfi mine_fileinfo; extern struct mh mine_header; extern struct me mine_editor; // returns 1 if error, else 0 int game_load_mine(char * filename); // loads from an already-open file // returns 0=everything ok, 1=old version, -1=error int load_mine_data(PHYSFS_file *LoadFile); int load_mine_data_compiled(PHYSFS_file *LoadFile); extern short tmap_xlate_table[]; #endif dxx-rebirth-0.58.1-d1x/main/gamerend.c000066400000000000000000000313471217717257200174340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Stuff for rendering the HUD * */ #include #include #include #include "timer.h" #include "pstypes.h" #include "console.h" #include "inferno.h" #include "dxxerror.h" #include "gr.h" #include "palette.h" #include "bm.h" #include "player.h" #include "render.h" #include "menu.h" #include "newmenu.h" #include "screens.h" #include "fix.h" #include "robot.h" #include "game.h" #include "gauges.h" #include "gamefont.h" #include "newdemo.h" #include "text.h" #include "multi.h" #include "endlevel.h" #include "cntrlcen.h" #include "fuelcen.h" #include "powerup.h" #include "laser.h" #include "playsave.h" #include "automap.h" #include "mission.h" #include "gameseq.h" #include "args.h" #ifdef OGL #include "ogl_init.h" #endif int netplayerinfo_on=0; #ifdef NETWORK void game_draw_multi_message() { if ( (Game_mode&GM_MULTI) && (multi_sending_message[Player_num])) { gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(0,63,0),-1); gr_printf(0x8000, (LINE_SPACING*5)+FSPACY(1), "%s: %s_", TXT_MESSAGE, Network_message ); } if ( (Game_mode&GM_MULTI) && (multi_defining_message)) { gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(0,63,0),-1); gr_printf(0x8000, (LINE_SPACING*5)+FSPACY(1), "%s #%d: %s_", TXT_MACRO, multi_defining_message, Network_message ); } } #endif void show_framerate() { static int fps_count = 0, fps_rate = 0; int y = GHEIGHT; static fix64 fps_time = 0; gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(0,31,0),-1); if (PlayerCfg.CockpitMode[1] == CM_FULL_SCREEN) { if ((Game_mode & GM_MULTI) || (Newdemo_state == ND_STATE_PLAYBACK && Newdemo_game_mode & GM_MULTI)) y -= LINE_SPACING * 10; else y -= LINE_SPACING * 4; } else if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { if ((Game_mode & GM_MULTI) || (Newdemo_state == ND_STATE_PLAYBACK && Newdemo_game_mode & GM_MULTI)) y -= LINE_SPACING * 6; else y -= LINE_SPACING * 1; } else { if ((Game_mode & GM_MULTI) || (Newdemo_state == ND_STATE_PLAYBACK && Newdemo_game_mode & GM_MULTI)) y -= LINE_SPACING * 7; else y -= LINE_SPACING * 2; } fps_count++; if (timer_query() >= fps_time + F1_0) { fps_rate = fps_count; fps_count = 0; fps_time = timer_query(); } gr_printf(SWIDTH-(GameArg.SysMaxFPS>999?FSPACX(43):FSPACX(37)),y,"FPS: %i",fps_rate); } #ifdef NETWORK void show_netplayerinfo() { int x=0, y=0, i=0, color=0, eff=0; static const char *const eff_strings[]={"trashing","really hurting","seriously effecting","hurting","effecting","tarnishing"}; gr_set_current_canvas(NULL); gr_set_curfont(GAME_FONT); gr_set_fontcolor(255,-1); x=(SWIDTH/2)-FSPACX(120); y=(SHEIGHT/2)-FSPACY(84); gr_settransblend(14, GR_BLEND_NORMAL); gr_setcolor( BM_XRGB(0,0,0) ); gr_rect((SWIDTH/2)-FSPACX(120),(SHEIGHT/2)-FSPACY(84),(SWIDTH/2)+FSPACX(120),(SHEIGHT/2)+FSPACY(84)); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); // general game information y+=LINE_SPACING; gr_printf(0x8000,y,"%s",Netgame.game_name); #ifndef SHAREWARE y+=LINE_SPACING; gr_printf(0x8000,y,"%s - lvl: %i",Netgame.mission_title,Netgame.levelnum); #endif x+=FSPACX(8); y+=LINE_SPACING*2; unsigned gamemode = Netgame.gamemode; gr_printf(x,y,"game mode: %s",gamemode < (sizeof(GMNames) / sizeof(GMNames[0])) ? GMNames[gamemode] : "INVALID"); y+=LINE_SPACING; gr_printf(x,y,"difficulty: %s",MENU_DIFFICULTY_TEXT(Netgame.difficulty)); y+=LINE_SPACING; gr_printf(x,y,"level time: %i:%02i:%02i",Players[Player_num].hours_level,f2i(Players[Player_num].time_level) / 60 % 60,f2i(Players[Player_num].time_level) % 60); y+=LINE_SPACING; gr_printf(x,y,"total time: %i:%02i:%02i",Players[Player_num].hours_total,f2i(Players[Player_num].time_total) / 60 % 60,f2i(Players[Player_num].time_total) % 60); y+=LINE_SPACING; if (Netgame.KillGoal) gr_printf(x,y,"Kill goal: %d",Netgame.KillGoal*5); // player information (name, kills, ping, game efficiency) y+=LINE_SPACING*2; gr_printf(x,y,"player"); if (Game_mode & GM_MULTI_COOP) gr_printf(x+FSPACX(8)*7,y,"score"); else { gr_printf(x+FSPACX(8)*7,y,"kills"); gr_printf(x+FSPACX(8)*12,y,"deaths"); } gr_printf(x+FSPACX(8)*18,y,"ping"); gr_printf(x+FSPACX(8)*23,y,"efficiency"); // process players table for (i=0; i 0 ) { char *viewer_name,*control_name; Show_view_text_timer -= FrameTime; switch( Viewer->type ) { case OBJ_FIREBALL: viewer_name = "Fireball"; break; case OBJ_ROBOT: viewer_name = "Robot"; break; case OBJ_HOSTAGE: viewer_name = "Hostage"; break; case OBJ_PLAYER: viewer_name = "Player"; break; case OBJ_WEAPON: viewer_name = "Weapon"; break; case OBJ_CAMERA: viewer_name = "Camera"; break; case OBJ_POWERUP: viewer_name = "Powerup"; break; case OBJ_DEBRIS: viewer_name = "Debris"; break; case OBJ_CNTRLCEN: viewer_name = "Control Center"; break; default: viewer_name = "Unknown"; break; } switch ( Viewer->control_type) { case CT_NONE: control_name = "Stopped"; break; case CT_AI: control_name = "AI"; break; case CT_FLYING: control_name = "Flying"; break; case CT_SLEW: control_name = "Slew"; break; case CT_FLYTHROUGH: control_name = "Flythrough"; break; case CT_MORPH: control_name = "Morphing"; break; default: control_name = "Unknown"; break; } gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(31,0,0),-1); gr_printf( 0x8000, (SHEIGHT/10), "%s View - %s",viewer_name,control_name ); } } #endif void render_countdown_gauge() { if (!Endlevel_sequence && Control_center_destroyed && (Countdown_seconds_left>-1) && (Countdown_seconds_left<127)) { gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(0,63,0),-1); gr_printf(0x8000, (LINE_SPACING*6)+FSPACY(1), "T-%d s", Countdown_seconds_left ); } } void game_draw_hud_stuff() { #ifdef CROSSHAIR if ( Viewer->type == OBJ_PLAYER ) laser_do_crosshair(Viewer); #endif #ifndef NDEBUG draw_window_label(); #endif #ifdef NETWORK game_draw_multi_message(); #endif if ((Newdemo_state == ND_STATE_PLAYBACK) || (Newdemo_state == ND_STATE_RECORDING)) { char message[128]; int y; if (Newdemo_state == ND_STATE_PLAYBACK) { if (Newdemo_show_percentage) { sprintf(message, "%s (%d%%%% %s)", TXT_DEMO_PLAYBACK, newdemo_get_percent_done(), TXT_DONE); } else { sprintf (message, " "); } } else { extern int Newdemo_num_written; sprintf (message, "%s (%dK)", TXT_DEMO_RECORDING, (Newdemo_num_written / 1024)); } gr_set_curfont( GAME_FONT ); gr_set_fontcolor( BM_XRGB(27,0,0), -1 ); y = GHEIGHT-(LINE_SPACING*2); if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) y = grd_curcanv->cv_bitmap.bm_h / 1.2 ; if (PlayerCfg.CockpitMode[1] != CM_REAR_VIEW) gr_string(0x8000, y, message ); } render_countdown_gauge(); if (GameCfg.FPSIndicator && PlayerCfg.CockpitMode[1] != CM_REAR_VIEW) show_framerate(); if (Newdemo_state == ND_STATE_PLAYBACK) Game_mode = Newdemo_game_mode; draw_hud(); if (Newdemo_state == ND_STATE_PLAYBACK) Game_mode = GM_NORMAL; if ( Player_is_dead ) player_dead_message(); } extern int gr_bitblt_dest_step_shift; extern int gr_bitblt_double; extern int force_cockpit_redraw; void update_cockpits(); //render a frame for the game void game_render_frame_mono(int flip) { gr_set_current_canvas(&Screen_3d_window); render_frame(0); update_cockpits(); if (Newdemo_state == ND_STATE_PLAYBACK) Game_mode = Newdemo_game_mode; if (PlayerCfg.CockpitMode[1]==CM_FULL_COCKPIT || PlayerCfg.CockpitMode[1]==CM_STATUS_BAR) render_gauges(); if (Newdemo_state == ND_STATE_PLAYBACK) Game_mode = GM_NORMAL; gr_set_current_canvas(&Screen_3d_window); game_draw_hud_stuff(); #ifdef NETWORK if (netplayerinfo_on && Game_mode & GM_MULTI) show_netplayerinfo(); #endif } void toggle_cockpit() { int new_mode=CM_FULL_SCREEN; if (Rear_view || Player_is_dead) return; switch (PlayerCfg.CockpitMode[1]) { case CM_FULL_COCKPIT: new_mode = CM_STATUS_BAR; break; case CM_STATUS_BAR: new_mode = CM_FULL_SCREEN; break; case CM_FULL_SCREEN: new_mode = CM_FULL_COCKPIT; break; } select_cockpit(new_mode); HUD_clear_messages(); PlayerCfg.CockpitMode[0] = new_mode; write_player_file(); } int last_drawn_cockpit = -1; extern void ogl_loadbmtexture(grs_bitmap *bm); // This actually renders the new cockpit onto the screen. void update_cockpits() { grs_bitmap *bm; PIGGY_PAGE_IN(cockpit_bitmap[PlayerCfg.CockpitMode[1]]); bm = &GameBitmaps[cockpit_bitmap[PlayerCfg.CockpitMode[1]].index]; switch( PlayerCfg.CockpitMode[1] ) { case CM_FULL_COCKPIT: gr_set_current_canvas(NULL); #ifdef OGL ogl_ubitmapm_cs (0, 0, -1, grd_curcanv->cv_bitmap.bm_h, bm,255, F1_0); #else gr_ubitmapm(0,0, bm); #endif break; case CM_REAR_VIEW: gr_set_current_canvas(NULL); #ifdef OGL ogl_ubitmapm_cs (0, 0, -1, grd_curcanv->cv_bitmap.bm_h, bm,255, F1_0); #else gr_ubitmapm(0,0, bm); #endif break; case CM_FULL_SCREEN: break; case CM_STATUS_BAR: gr_set_current_canvas(NULL); #ifdef OGL ogl_ubitmapm_cs (0, (HIRESMODE?(SHEIGHT*2)/2.6:(SHEIGHT*2)/2.72), -1, ((int) ((double) (bm->bm_h) * (HIRESMODE?(double)SHEIGHT/480:(double)SHEIGHT/200) + 0.5)), bm,255, F1_0); #else gr_ubitmapm(0,SHEIGHT-bm->bm_h,bm); #endif break; case CM_LETTERBOX: gr_set_current_canvas(NULL); break; } gr_set_current_canvas(NULL); if (PlayerCfg.CockpitMode[1] != last_drawn_cockpit) last_drawn_cockpit = PlayerCfg.CockpitMode[1]; else return; if (PlayerCfg.CockpitMode[1]==CM_FULL_COCKPIT || PlayerCfg.CockpitMode[1]==CM_STATUS_BAR) init_gauges(); } void game_render_frame() { set_screen_mode( SCREEN_GAME ); play_homing_warning(); game_render_frame_mono(GameArg.DbgUseDoubleBuffer); } //show a message in a nice little box void show_boxed_message(char *msg, int RenderFlag) { int w,h,aw; int x,y; gr_set_current_canvas(NULL); gr_set_curfont( MEDIUM1_FONT ); gr_set_fontcolor(BM_XRGB(31, 31, 31), -1); gr_get_string_size(msg,&w,&h,&aw); x = (SWIDTH-w)/2; y = (SHEIGHT-h)/2; nm_draw_background(x-BORDERX,y-BORDERY,x+w+BORDERX,y+h+BORDERY); gr_string( 0x8000, y, msg ); // If we haven't drawn behind it, need to flip if (!RenderFlag) gr_flip(); } dxx-rebirth-0.58.1-d1x/main/gamesave.c000066400000000000000000001166161217717257200174450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Save game information * */ #include #include #include "pstypes.h" #include "strutil.h" #include "console.h" #include "key.h" #include "gr.h" #include "palette.h" #include "newmenu.h" #include "inferno.h" #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #include "editor/eswitch.h" #endif #include "dxxerror.h" #include "object.h" #include "game.h" #include "screens.h" #include "wall.h" #include "gamemine.h" #include "robot.h" #include "bm.h" #include "menu.h" #include "switch.h" #include "fuelcen.h" #include "cntrlcen.h" #include "powerup.h" #include "hostage.h" #include "weapon.h" #include "newdemo.h" #include "gameseq.h" #include "automap.h" #include "polyobj.h" #include "text.h" #include "gamefont.h" #include "gamesave.h" #include "textures.h" #include "multi.h" #include "makesig.h" #ifndef NDEBUG void dump_mine_info(void); #endif #ifdef EDITOR #ifdef SHAREWARE char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = { "level01.sdl", "level02.sdl", "level03.sdl", "level04.sdl", "level05.sdl", "level06.sdl", "level07.sdl" }; #else char *Shareware_level_names[NUM_SHAREWARE_LEVELS] = { "level01.rdl", "level02.rdl", "level03.rdl", "level04.rdl", "level05.rdl", "level06.rdl", "level07.rdl" }; #endif char *Registered_level_names[NUM_REGISTERED_LEVELS] = { "level08.rdl", "level09.rdl", "level10.rdl", "level11.rdl", "level12.rdl", "level13.rdl", "level14.rdl", "level15.rdl", "level16.rdl", "level17.rdl", "level18.rdl", "level19.rdl", "level20.rdl", "level21.rdl", "level22.rdl", "level23.rdl", "level24.rdl", "level25.rdl", "level26.rdl", "level27.rdl", "levels1.rdl", "levels2.rdl", "levels3.rdl" }; #endif char Gamesave_current_filename[PATH_MAX]; int Gamesave_current_version; #define GAME_VERSION 25 #define GAME_COMPATIBLE_VERSION 22 #define MENU_CURSOR_X_MIN MENU_X #define MENU_CURSOR_X_MAX MENU_X+6 #define HOSTAGE_DATA_VERSION 0 #ifdef EDITOR struct { ushort fileinfo_signature; ushort fileinfo_version; int fileinfo_sizeof; } game_top_fileinfo; // Should be same as first two fields below... struct { ushort fileinfo_signature; ushort fileinfo_version; int fileinfo_sizeof; char mine_filename[15]; int level; int player_offset; // Player info int player_sizeof; int object_offset; // Object info int object_howmany; int object_sizeof; int walls_offset; int walls_howmany; int walls_sizeof; int doors_offset; int doors_howmany; int doors_sizeof; int triggers_offset; int triggers_howmany; int triggers_sizeof; int links_offset; int links_howmany; int links_sizeof; int control_offset; int control_howmany; int control_sizeof; int matcen_offset; int matcen_howmany; int matcen_sizeof; } game_fileinfo; #endif // EDITOR // LINT: adding function prototypes void read_object(object *obj, PHYSFS_file *f, int version); #ifdef EDITOR void write_object(object *obj, PHYSFS_file *f); void do_load_save_levels(int save); #endif #ifndef NDEBUG void dump_mine_info(void); #endif extern char MaxPowerupsAllowed[MAX_POWERUP_TYPES]; extern char PowerupsInMine[MAX_POWERUP_TYPES]; #ifdef EDITOR extern char mine_filename[]; extern int save_mine_data_compiled(PHYSFS_file *SaveFile); //--unused-- #else //--unused-- char mine_filename[128]; #endif int Gamesave_num_org_robots = 0; //--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL; #ifdef EDITOR // Return true if this level has a name of the form "level??" // Note that a pathspec can appear at the beginning of the filename. int is_real_level(char *filename) { int len = strlen(filename); if (len < 6) return 0; return !d_strnicmp(&filename[len-11], "level", 5); } #endif //--unused-- vms_angvec zero_angles={0,0,0}; #define vm_angvec_zero(v) do {(v)->p=(v)->b=(v)->h=0;} while (0) int Gamesave_num_players=0; int N_save_pof_names=25; #define MAX_POLYGON_MODELS_NEW 167 char Save_pof_names[MAX_POLYGON_MODELS_NEW][FILENAME_LEN]; static int convert_vclip(int vc) { if (vc < 0) return vc; if ((vc < VCLIP_MAXNUM) && (Vclip[vc].num_frames >= 0)) return vc; return 0; } static int convert_wclip(int wc) { return (wc < Num_wall_anims) ? wc : wc % Num_wall_anims; } int convert_tmap(int tmap) { return (tmap >= NumTextures) ? tmap % NumTextures : tmap; } static int convert_polymod(int polymod) { return (polymod >= N_polygon_models) ? polymod % N_polygon_models : polymod; } void check_and_fix_matrix(vms_matrix *m); void verify_object( object * obj ) { obj->lifeleft = IMMORTAL_TIME; //all loaded object are immortal, for now if ( obj->type == OBJ_ROBOT ) { Gamesave_num_org_robots++; // Make sure valid id... if ( obj->id >= N_robot_types ) obj->id = obj->id % N_robot_types; // Make sure model number & size are correct... if ( obj->render_type == RT_POLYOBJ ) { obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->size = Polygon_models[obj->rtype.pobj_info.model_num].rad; //@@if (obj->control_type==CT_AI && Robot_info[obj->id].attack_type) //@@ obj->size = obj->size*3/4; } if (obj->movement_type == MT_PHYSICS) { obj->mtype.phys_info.mass = Robot_info[obj->id].mass; obj->mtype.phys_info.drag = Robot_info[obj->id].drag; } } else { //Robots taken care of above if ( obj->render_type == RT_POLYOBJ ) { int i; char *name = Save_pof_names[obj->rtype.pobj_info.model_num]; for (i=0;irtype.pobj_info.model_num = i; break; } } } if ( obj->type == OBJ_POWERUP ) { if ( obj->id >= N_powerup_types ) { obj->id = 0; Assert( obj->render_type != RT_POLYOBJ ); } obj->control_type = CT_POWERUP; obj->size = Powerup_info[obj->id].size; if (Game_mode & GM_NETWORK) { if (multi_powerup_is_4pack(obj->id)) { PowerupsInMine[obj->id-1]+=4; MaxPowerupsAllowed[obj->id-1]+=4; } else { PowerupsInMine[obj->id]++; MaxPowerupsAllowed[obj->id]++; } } } if ( obj->type == OBJ_WEAPON ) { if ( obj->id >= N_weapon_types ) { obj->id = 0; Assert( obj->render_type != RT_POLYOBJ ); } } if ( obj->type == OBJ_CNTRLCEN ) { int i; obj->render_type = RT_POLYOBJ; obj->control_type = CT_CNTRLCEN; // Make model number is correct... for (i=0; irtype.pobj_info.model_num = ObjId[i]; obj->shields = ObjStrength[i]; break; } } if ( obj->type == OBJ_PLAYER ) { //int i; //Assert(obj == Player); if ( obj == ConsoleObject ) init_player_object(); else if (obj->render_type == RT_POLYOBJ) //recover from Matt's pof file matchup bug obj->rtype.pobj_info.model_num = Player_ship->model_num; //Make sure orient matrix is orthogonal check_and_fix_matrix(&obj->orient); obj->id = Gamesave_num_players++; } if (obj->type == OBJ_HOSTAGE) { if (obj->id > N_hostage_types) obj->id = 0; obj->render_type = RT_HOSTAGE; obj->control_type = CT_POWERUP; } } //static gs_skip(int len,PHYSFS_file *file) //{ // // PHYSFSX_fseek(file,len,SEEK_CUR); //} //reads one object of the given version from the given file void read_object(object *obj,PHYSFS_file *f,int version) { obj->type = PHYSFSX_readByte(f); obj->id = PHYSFSX_readByte(f); if (obj->type == OBJ_ROBOT && obj->id > 23) { obj->id = obj->id % 24; } obj->control_type = PHYSFSX_readByte(f); obj->movement_type = PHYSFSX_readByte(f); obj->render_type = PHYSFSX_readByte(f); obj->flags = PHYSFSX_readByte(f); obj->segnum = PHYSFSX_readShort(f); obj->attached_obj = -1; PHYSFSX_readVector(&obj->pos,f); PHYSFSX_readMatrix(&obj->orient,f); obj->size = PHYSFSX_readFix(f); obj->shields = PHYSFSX_readFix(f); PHYSFSX_readVector(&obj->last_pos,f); obj->contains_type = PHYSFSX_readByte(f); obj->contains_id = PHYSFSX_readByte(f); obj->contains_count = PHYSFSX_readByte(f); switch (obj->movement_type) { case MT_PHYSICS: PHYSFSX_readVector(&obj->mtype.phys_info.velocity,f); PHYSFSX_readVector(&obj->mtype.phys_info.thrust,f); obj->mtype.phys_info.mass = PHYSFSX_readFix(f); obj->mtype.phys_info.drag = PHYSFSX_readFix(f); obj->mtype.phys_info.brakes = PHYSFSX_readFix(f); PHYSFSX_readVector(&obj->mtype.phys_info.rotvel,f); PHYSFSX_readVector(&obj->mtype.phys_info.rotthrust,f); obj->mtype.phys_info.turnroll = PHYSFSX_readFixAng(f); obj->mtype.phys_info.flags = PHYSFSX_readShort(f); break; case MT_SPINNING: PHYSFSX_readVector(&obj->mtype.spin_rate,f); break; case MT_NONE: break; default: Int3(); } switch (obj->control_type) { case CT_AI: { int i; obj->ctype.ai_info.behavior = PHYSFSX_readByte(f); for (i=0;ictype.ai_info.flags[i] = PHYSFSX_readByte(f); obj->ctype.ai_info.hide_segment = PHYSFSX_readShort(f); obj->ctype.ai_info.hide_index = PHYSFSX_readShort(f); obj->ctype.ai_info.path_length = PHYSFSX_readShort(f); obj->ctype.ai_info.cur_path_index = PHYSFSX_readShort(f); if (version <= 25) { obj->ctype.ai_info.follow_path_start_seg = PHYSFSX_readShort(f); obj->ctype.ai_info.follow_path_end_seg = PHYSFSX_readShort(f); } break; } case CT_EXPLOSION: obj->ctype.expl_info.spawn_time = PHYSFSX_readFix(f); obj->ctype.expl_info.delete_time = PHYSFSX_readFix(f); obj->ctype.expl_info.delete_objnum = PHYSFSX_readShort(f); obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1; break; case CT_WEAPON: //do I really need to read these? Are they even saved to disk? obj->ctype.laser_info.parent_type = PHYSFSX_readShort(f); obj->ctype.laser_info.parent_num = PHYSFSX_readShort(f); obj->ctype.laser_info.parent_signature = PHYSFSX_readInt(f); break; case CT_LIGHT: obj->ctype.light_info.intensity = PHYSFSX_readFix(f); break; case CT_POWERUP: if (version >= 25) obj->ctype.powerup_info.count = PHYSFSX_readInt(f); else obj->ctype.powerup_info.count = 1; if (obj->id == POW_VULCAN_WEAPON) obj->ctype.powerup_info.count = VULCAN_WEAPON_AMMO_AMOUNT; break; case CT_NONE: case CT_FLYING: case CT_DEBRIS: break; case CT_SLEW: //the player is generally saved as slew break; case CT_CNTRLCEN: break; case CT_MORPH: case CT_FLYTHROUGH: case CT_REPAIRCEN: default: Int3(); } switch (obj->render_type) { case RT_NONE: break; case RT_MORPH: case RT_POLYOBJ: { int i,tmo; obj->rtype.pobj_info.model_num = convert_polymod(PHYSFSX_readInt(f)); for (i=0;irtype.pobj_info.anim_angles[i],f); obj->rtype.pobj_info.subobj_flags = PHYSFSX_readInt(f); tmo = PHYSFSX_readInt(f); #ifndef EDITOR obj->rtype.pobj_info.tmap_override = convert_tmap(tmo); #else if (tmo==-1) obj->rtype.pobj_info.tmap_override = -1; else { int xlated_tmo = tmap_xlate_table[tmo]; if (xlated_tmo < 0) { Int3(); xlated_tmo = 0; } obj->rtype.pobj_info.tmap_override = xlated_tmo; } #endif obj->rtype.pobj_info.alt_textures = 0; break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj->rtype.vclip_info.vclip_num = convert_vclip(PHYSFSX_readInt(f)); obj->rtype.vclip_info.frametime = PHYSFSX_readFix(f); obj->rtype.vclip_info.framenum = PHYSFSX_readByte(f); break; case RT_LASER: break; default: Int3(); } } #ifdef EDITOR //writes one object to the given file void write_object(object *obj, PHYSFS_file *f) { PHYSFSX_writeU8(f, obj->type); PHYSFSX_writeU8(f, obj->id); PHYSFSX_writeU8(f, obj->control_type); PHYSFSX_writeU8(f, obj->movement_type); PHYSFSX_writeU8(f, obj->render_type); PHYSFSX_writeU8(f, obj->flags); PHYSFS_writeSLE16(f, obj->segnum); PHYSFSX_writeVector(f, &obj->pos); PHYSFSX_writeMatrix(f, &obj->orient); PHYSFSX_writeFix(f, obj->size); PHYSFSX_writeFix(f, obj->shields); PHYSFSX_writeVector(f, &obj->last_pos); PHYSFSX_writeU8(f, obj->contains_type); PHYSFSX_writeU8(f, obj->contains_id); PHYSFSX_writeU8(f, obj->contains_count); switch (obj->movement_type) { case MT_PHYSICS: PHYSFSX_writeVector(f, &obj->mtype.phys_info.velocity); PHYSFSX_writeVector(f, &obj->mtype.phys_info.thrust); PHYSFSX_writeFix(f, obj->mtype.phys_info.mass); PHYSFSX_writeFix(f, obj->mtype.phys_info.drag); PHYSFSX_writeFix(f, obj->mtype.phys_info.brakes); PHYSFSX_writeVector(f, &obj->mtype.phys_info.rotvel); PHYSFSX_writeVector(f, &obj->mtype.phys_info.rotthrust); PHYSFSX_writeFixAng(f, obj->mtype.phys_info.turnroll); PHYSFS_writeSLE16(f, obj->mtype.phys_info.flags); break; case MT_SPINNING: PHYSFSX_writeVector(f, &obj->mtype.spin_rate); break; case MT_NONE: break; default: Int3(); } switch (obj->control_type) { case CT_AI: { int i; PHYSFSX_writeU8(f, obj->ctype.ai_info.behavior); for (i = 0; i < MAX_AI_FLAGS; i++) PHYSFSX_writeU8(f, obj->ctype.ai_info.flags[i]); PHYSFS_writeSLE16(f, obj->ctype.ai_info.hide_segment); PHYSFS_writeSLE16(f, obj->ctype.ai_info.hide_index); PHYSFS_writeSLE16(f, obj->ctype.ai_info.path_length); PHYSFS_writeSLE16(f, obj->ctype.ai_info.cur_path_index); PHYSFS_writeSLE16(f, obj->ctype.ai_info.follow_path_start_seg); PHYSFS_writeSLE16(f, obj->ctype.ai_info.follow_path_end_seg); break; } case CT_EXPLOSION: PHYSFSX_writeFix(f, obj->ctype.expl_info.spawn_time); PHYSFSX_writeFix(f, obj->ctype.expl_info.delete_time); PHYSFS_writeSLE16(f, obj->ctype.expl_info.delete_objnum); break; case CT_WEAPON: //do I really need to write these objects? PHYSFS_writeSLE16(f, obj->ctype.laser_info.parent_type); PHYSFS_writeSLE16(f, obj->ctype.laser_info.parent_num); PHYSFS_writeSLE32(f, obj->ctype.laser_info.parent_signature); break; case CT_LIGHT: PHYSFSX_writeFix(f, obj->ctype.light_info.intensity); break; case CT_POWERUP: PHYSFS_writeSLE32(f, obj->ctype.powerup_info.count); break; case CT_NONE: case CT_FLYING: case CT_DEBRIS: break; case CT_SLEW: //the player is generally saved as slew break; case CT_CNTRLCEN: break; //control center object. case CT_MORPH: case CT_REPAIRCEN: case CT_FLYTHROUGH: default: Int3(); } switch (obj->render_type) { case RT_NONE: break; case RT_MORPH: case RT_POLYOBJ: { int i; PHYSFS_writeSLE32(f, obj->rtype.pobj_info.model_num); for (i = 0; i < MAX_SUBMODELS; i++) PHYSFSX_writeAngleVec(f, &obj->rtype.pobj_info.anim_angles[i]); PHYSFS_writeSLE32(f, obj->rtype.pobj_info.subobj_flags); PHYSFS_writeSLE32(f, obj->rtype.pobj_info.tmap_override); break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: PHYSFS_writeSLE32(f, obj->rtype.vclip_info.vclip_num); PHYSFSX_writeFix(f, obj->rtype.vclip_info.frametime); PHYSFSX_writeU8(f, obj->rtype.vclip_info.framenum); break; case RT_LASER: break; default: Int3(); } } #endif // -------------------------------------------------------------------- // Load game // Loads all the relevant data for a level. // If level != -1, it loads the filename with extension changed to .min // Otherwise it loads the appropriate level mine. // returns 0=everything ok, 1=old version, -1=error int load_game_data(PHYSFS_file *LoadFile) { int i,j; short game_top_fileinfo_version; int object_offset; int gs_num_objects; int trig_size; //===================== READ FILE INFO ======================== #if 0 PHYSFS_read(LoadFile, &game_top_fileinfo, sizeof(game_top_fileinfo), 1); #endif // Check signature if (PHYSFSX_readShort(LoadFile) != 0x6705) return -1; // Read and check version number game_top_fileinfo_version = PHYSFSX_readShort(LoadFile); if (game_top_fileinfo_version < GAME_COMPATIBLE_VERSION ) return -1; // We skip some parts of the former game_top_fileinfo PHYSFSX_fseek(LoadFile, 31, SEEK_CUR); object_offset = PHYSFSX_readInt(LoadFile); gs_num_objects = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile, 8, SEEK_CUR); Num_walls = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile, 20, SEEK_CUR); Num_triggers = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile, 24, SEEK_CUR); trig_size = PHYSFSX_readInt(LoadFile); Assert(trig_size == sizeof(ControlCenterTriggers)); (void)trig_size; PHYSFSX_fseek(LoadFile, 4, SEEK_CUR); Num_robot_centers = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile, 4, SEEK_CUR); if (game_top_fileinfo_version >= 31) //load mine filename // read newline-terminated string, not sure what version this changed. PHYSFSX_fgets(Current_level_name,sizeof(Current_level_name),LoadFile); else if (game_top_fileinfo_version >= 14) { //load mine filename // read null-terminated string char *p=Current_level_name; //must do read one char at a time, since no PHYSFSX_fgets() do *p = PHYSFSX_fgetc(LoadFile); while (*p++!=0); } else Current_level_name[0]=0; if (game_top_fileinfo_version >= 19) { //load pof names N_save_pof_names = PHYSFSX_readShort(LoadFile); if (N_save_pof_names != 0x614d && N_save_pof_names != 0x5547) { // "Ma"de w/DMB beta/"GU"ILE Assert(N_save_pof_names < MAX_POLYGON_MODELS); PHYSFS_read(LoadFile,Save_pof_names,N_save_pof_names,FILENAME_LEN); } } //===================== READ PLAYER INFO ========================== //===================== READ OBJECT INFO ========================== Gamesave_num_org_robots = 0; Gamesave_num_players = 0; if (object_offset > -1) { if (PHYSFSX_fseek( LoadFile, object_offset, SEEK_SET )) Error( "Error seeking to object_offset in gamesave.c" ); for (i = 0; i < gs_num_objects; i++) { read_object(&Objects[i], LoadFile, game_top_fileinfo_version); Objects[i].signature = obj_get_signature(); verify_object( &Objects[i] ); } } //===================== READ WALL INFO ============================ for (i = 0; i < Num_walls; i++) { if (game_top_fileinfo_version >= 20) wall_read(&Walls[i], LoadFile); // v20 walls and up. else if (game_top_fileinfo_version >= 17) { v19_wall w; v19_wall_read(&w, LoadFile); Walls[i].segnum = w.segnum; Walls[i].sidenum = w.sidenum; Walls[i].linked_wall = w.linked_wall; Walls[i].type = w.type; Walls[i].flags = w.flags; Walls[i].hps = w.hps; Walls[i].trigger = w.trigger; Walls[i].clip_num = convert_wclip(w.clip_num); Walls[i].keys = w.keys; Walls[i].state = WALL_DOOR_CLOSED; } else { v16_wall w; v16_wall_read(&w, LoadFile); Walls[i].segnum = Walls[i].sidenum = Walls[i].linked_wall = -1; Walls[i].type = w.type; Walls[i].flags = w.flags; Walls[i].hps = w.hps; Walls[i].trigger = w.trigger; Walls[i].clip_num = convert_wclip(w.clip_num); Walls[i].keys = w.keys; } } #if 0 //===================== READ DOOR INFO ============================ if (game_fileinfo.doors_offset > -1) { if (!PHYSFSX_fseek( LoadFile, game_fileinfo.doors_offset,SEEK_SET )) { for (i=0;i= 20) active_door_read(&ActiveDoors[i], LoadFile); // version 20 and up else { v19_door d; int p; v19_door_read(&d, LoadFile); ActiveDoors[i].n_parts = d.n_parts; for (p=0;p Highest_segment_index) //bogus object Objects[i].type = OBJ_NONE; else { Objects[i].segnum = -1; //avoid Assert() obj_link(i,objsegnum); } } } clear_transient_objects(1); //1 means clear proximity bombs // Make sure non-transparent doors are set correctly. for (i=0; i< Num_segments; i++) for (j=0;jwall_num != -1) && (Walls[sidep->wall_num].clip_num != -1)) { if (WallAnims[Walls[sidep->wall_num].clip_num].flags & WCF_TMAP1) { sidep->tmap_num = WallAnims[Walls[sidep->wall_num].clip_num].frames[0]; sidep->tmap_num2 = 0; } } } reset_walls(); #if 0 Num_open_doors = game_fileinfo.doors_howmany; #endif // 0 Num_open_doors = 0; //go through all walls, killing references to invalid triggers for (i=0;i= Num_triggers) { Walls[i].trigger = -1; //kill trigger } //go through all triggers, killing unused ones for (i=0;i\n",filename); #endif } strcpy( Gamesave_current_filename, filename ); sig = PHYSFSX_readInt(LoadFile); Gamesave_current_version = PHYSFSX_readInt(LoadFile); minedata_offset = PHYSFSX_readInt(LoadFile); gamedata_offset = PHYSFSX_readInt(LoadFile); Assert(sig == MAKE_SIG('P','L','V','L')); (void)sig; if (Gamesave_current_version < 5) hostagetext_offset = PHYSFSX_readInt(LoadFile); PHYSFSX_fseek(LoadFile,minedata_offset,SEEK_SET); #ifdef EDITOR if (!use_compiled_level) mine_err = load_mine_data(LoadFile); else #endif //NOTE LINK TO ABOVE!! mine_err = load_mine_data_compiled(LoadFile); /* !!!HACK!!! * Descent 1 - Level 19: OBERON MINE has some ugly overlapping rooms (segment 484). * HACK to make this issue less visible by moving one vertex a little. */ if (Current_mission && !d_stricmp("Descent: First Strike",Current_mission_longname) && !d_stricmp("level19.rdl",filename) && PHYSFS_fileLength(LoadFile) == 136706) Vertices[1905].z =-385*F1_0; if (mine_err == -1) { //error!! PHYSFS_close(LoadFile); return 2; } PHYSFSX_fseek(LoadFile,gamedata_offset,SEEK_SET); game_err = load_game_data(LoadFile); if (game_err == -1) { //error!! PHYSFS_close(LoadFile); return 3; } (void)hostagetext_offset; //======================== CLOSE FILE ============================= PHYSFS_close( LoadFile ); #if 0 //def EDITOR #ifndef RELEASE write_game_text_file(filename); if (Errors_in_mine) { if (is_real_level(filename)) { char ErrorMessage[200]; sprintf( ErrorMessage, "Warning: %i errors in %s!\n", Errors_in_mine, Level_being_loaded ); stop_time(); gr_palette_load(gr_palette); nm_messagebox( NULL, 1, "Continue", ErrorMessage ); start_time(); } } #endif #endif #ifdef EDITOR //If an old version, ask the use if he wants to save as new version if (((LEVEL_FILE_VERSION>1) && Gamesave_current_version= 0; } #endif #ifdef EDITOR // -------------------------------------------------------------------------------------- // Create a new mine, set global variables. int create_new_mine(void) { int s; vms_vector sizevec; vms_matrix m1 = IDENTITY_MATRIX; // initialize_mine_arrays(); // gamestate_not_restored = 1; // Clear refueling center code fuelcen_reset(); hostage_init_all(); init_all_vertices(); Current_level_num = 0; //0 means not a real level Current_level_name[0] = 0; Gamesave_current_version = LEVEL_FILE_VERSION; Cur_object_index = -1; reset_objects(1); //just one object, the player num_groups = 0; current_group = -1; Num_vertices = 0; // Number of vertices in global array. Highest_vertex_index = 0; Num_segments = 0; // Number of segments in global array, will get increased in med_create_segment Highest_segment_index = 0; Cursegp = Segments; // Say current segment is the only segment. Curside = WBACK; // The active side is the back side Markedsegp = 0; // Say there is no marked segment. Markedside = WBACK; // Shouldn't matter since Markedsegp == 0, but just in case... for (s=0;s= 5 ? 31 : GAME_VERSION; int player_offset=0, object_offset=0, walls_offset=0, doors_offset=0, triggers_offset=0, control_offset=0, matcen_offset=0; //, links_offset; int offset_offset=0, end_offset=0; int i; //===================== SAVE FILE INFO ======================== PHYSFS_writeSLE16(SaveFile, 0x6705); // signature PHYSFS_writeSLE16(SaveFile, game_top_fileinfo_version); PHYSFS_writeSLE32(SaveFile, sizeof(game_fileinfo)); PHYSFS_write(SaveFile, Current_level_name, 15, 1); PHYSFS_writeSLE32(SaveFile, Current_level_num); offset_offset = PHYSFS_tell(SaveFile); // write the offsets later PHYSFS_writeSLE32(SaveFile, -1); PHYSFS_writeSLE32(SaveFile, sizeof(player)); #define WRITE_HEADER_ENTRY(t, n) do { PHYSFS_writeSLE32(SaveFile, -1); PHYSFS_writeSLE32(SaveFile, n); PHYSFS_writeSLE32(SaveFile, sizeof(t)); } while(0) WRITE_HEADER_ENTRY(object, Highest_object_index + 1); WRITE_HEADER_ENTRY(wall, Num_walls); WRITE_HEADER_ENTRY(active_door, Num_open_doors); WRITE_HEADER_ENTRY(trigger, Num_triggers); WRITE_HEADER_ENTRY(0, 0); // links (removed by Parallax) WRITE_HEADER_ENTRY(control_center_triggers, 1); WRITE_HEADER_ENTRY(matcen_info, Num_robot_centers); // Write the mine name PHYSFSX_printf(SaveFile, "%s\n", Current_level_name); PHYSFS_writeSLE16(SaveFile, N_polygon_models); PHYSFS_write(SaveFile, Pof_names, sizeof(*Pof_names), N_polygon_models); //==================== SAVE PLAYER INFO =========================== player_offset = PHYSFS_tell(SaveFile); PHYSFS_write(SaveFile, &Players[Player_num], sizeof(player), 1); // not endian friendly, but not used either //==================== SAVE OBJECT INFO =========================== object_offset = PHYSFS_tell(SaveFile); //fwrite( &Objects, sizeof(object), game_fileinfo.object_howmany, SaveFile ); for (i = 0; i <= Highest_object_index; i++) write_object(&Objects[i], SaveFile); //==================== SAVE WALL INFO ============================= walls_offset = PHYSFS_tell(SaveFile); for (i = 0; i < Num_walls; i++) wall_write(&Walls[i], game_top_fileinfo_version, SaveFile); //==================== SAVE DOOR INFO ============================= #if 0 // FIXME: okay to leave this out? doors_offset = PHYSFS_tell(SaveFile); for (i = 0; i < Num_open_doors; i++) door_write(&ActiveDoors[i], game_top_fileinfo_version, SaveFile); #endif //==================== SAVE TRIGGER INFO ============================= triggers_offset = PHYSFS_tell(SaveFile); for (i = 0; i < Num_triggers; i++) trigger_write(&Triggers[i], game_top_fileinfo_version, SaveFile); //================ SAVE CONTROL CENTER TRIGGER INFO =============== control_offset = PHYSFS_tell(SaveFile); control_center_triggers_write(&ControlCenterTriggers, SaveFile); //================ SAVE MATERIALIZATION CENTER TRIGGER INFO =============== matcen_offset = PHYSFS_tell(SaveFile); for (i = 0; i < Num_robot_centers; i++) matcen_info_write(&RobotCenters[i], game_top_fileinfo_version, SaveFile); //============= REWRITE FILE INFO, TO SAVE OFFSETS =============== end_offset = PHYSFS_tell(SaveFile); // Update the offset fields #define WRITE_OFFSET(o, n) do { PHYSFS_seek(SaveFile, offset_offset); PHYSFS_writeSLE32(SaveFile, o ## _offset); offset_offset += sizeof(int)*n; } while (0) WRITE_OFFSET(player, 2); WRITE_OFFSET(object, 3); WRITE_OFFSET(walls, 3); WRITE_OFFSET(doors, 3); WRITE_OFFSET(triggers, 6); WRITE_OFFSET(control, 3); WRITE_OFFSET(matcen, 3); // Go back to end of data PHYSFS_seek(SaveFile, end_offset); return 0; } int save_mine_data(PHYSFS_file * SaveFile); // ----------------------------------------------------------------------------- // Save game int save_level_sub(char * filename, int compiled_version) { PHYSFS_file * SaveFile; char temp_filename[PATH_MAX]; int minedata_offset=0,gamedata_offset=0,hostagetext_offset=0; // if ( !compiled_version ) { write_game_text_file(filename); if (Errors_in_mine) { if (is_real_level(filename)) { char ErrorMessage[200]; sprintf( ErrorMessage, "Warning: %i errors in this mine!\n", Errors_in_mine ); gr_palette_load(gr_palette); if (nm_messagebox( NULL, 2, "Cancel Save", "Save", ErrorMessage )!=1) { return 1; } } } // change_filename_extension(temp_filename,filename,".LVL"); } // else { change_filename_extension(temp_filename, filename, ".RDL"); } SaveFile = PHYSFSX_openWriteBuffered(temp_filename); if (!SaveFile) { char ErrorMessage[256]; snprintf( ErrorMessage, sizeof(ErrorMessage), "ERROR: Cannot write to '%s'.", temp_filename); gr_palette_load(gr_palette); nm_messagebox( NULL, 1, "Ok", ErrorMessage ); return 1; } if (Current_level_name[0] == 0) strcpy(Current_level_name,"Untitled"); clear_transient_objects(1); //1 means clear proximity bombs compress_objects(); //after this, Highest_object_index == num objects //make sure player is in a segment if (update_object_seg(&Objects[Players[0].objnum]) == 0) { if (ConsoleObject->segnum > Highest_segment_index) ConsoleObject->segnum = 0; compute_segment_center(&ConsoleObject->pos,&(Segments[ConsoleObject->segnum])); } fix_object_segs(); //Write the header PHYSFS_writeSLE32(SaveFile, MAKE_SIG('P','L','V','L')); PHYSFS_writeSLE32(SaveFile, Gamesave_current_version); //save placeholders PHYSFS_writeSLE32(SaveFile, minedata_offset); PHYSFS_writeSLE32(SaveFile, gamedata_offset); PHYSFS_writeSLE32(SaveFile, hostagetext_offset); //Now write the damn data minedata_offset = PHYSFS_tell(SaveFile); #if 0 // only save compiled mine data if ( !compiled_version ) save_mine_data(SaveFile); else #endif save_mine_data_compiled(SaveFile); gamedata_offset = PHYSFS_tell(SaveFile); save_game_data(SaveFile); hostagetext_offset = PHYSFS_tell(SaveFile); PHYSFS_seek(SaveFile, sizeof(int) + sizeof(Gamesave_current_version)); PHYSFS_writeSLE32(SaveFile, minedata_offset); PHYSFS_writeSLE32(SaveFile, gamedata_offset); PHYSFS_writeSLE32(SaveFile, hostagetext_offset); //==================== CLOSE THE FILE ============================= PHYSFS_close(SaveFile); // if ( !compiled_version ) { if (EditorWindow) editor_status_fmt("Saved mine %s, \"%s\"",filename,Current_level_name); } return 0; } int save_level(char * filename) { int r1; // Save normal version... //save_level_sub(filename, 0); // just save compiled one // Save compiled version... r1 = save_level_sub(filename, 1); return r1; } #endif //EDITOR #ifndef NDEBUG void dump_mine_info(void) { int segnum, sidenum; fix min_u, max_u, min_v, max_v, min_l, max_l, max_sl; min_u = F1_0*1000; min_v = min_u; min_l = min_u; max_u = -min_u; max_v = max_u; max_l = max_u; max_sl = 0; for (segnum=0; segnum<=Highest_segment_index; segnum++) { for (sidenum=0; sidenum max_sl) max_sl = Segments[segnum].static_light; for (vertnum=0; vertnum<4; vertnum++) { if (sidep->uvls[vertnum].u < min_u) min_u = sidep->uvls[vertnum].u; else if (sidep->uvls[vertnum].u > max_u) max_u = sidep->uvls[vertnum].u; if (sidep->uvls[vertnum].v < min_v) min_v = sidep->uvls[vertnum].v; else if (sidep->uvls[vertnum].v > max_v) max_v = sidep->uvls[vertnum].v; if (sidep->uvls[vertnum].l < min_l) min_l = sidep->uvls[vertnum].l; else if (sidep->uvls[vertnum].l > max_l) max_l = sidep->uvls[vertnum].l; } } } } #endif dxx-rebirth-0.58.1-d1x/main/gamesave.h000066400000000000000000000026351217717257200174450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Headers for gamesave.c * */ #ifndef _GAMESAVE_H #define _GAMESAVE_H #define NUM_SHAREWARE_LEVELS 7 #define NUM_REGISTERED_LEVELS 23 extern char *Shareware_level_names[NUM_SHAREWARE_LEVELS]; extern char *Registered_level_names[NUM_REGISTERED_LEVELS]; int convert_tmap(int tmap); // for gamemine.c void LoadGame(void); void SaveGame(void); int get_level_name(void); extern int load_level(const char *filename); extern int save_level(char *filename); extern char Gamesave_current_filename[]; extern int Gamesave_current_version; extern int Gamesave_num_org_robots; // In dumpmine.c extern void write_game_text_file(char *filename); extern int Errors_in_mine; #endif /* _GAMESAVE_H */ dxx-rebirth-0.58.1-d1x/main/gameseg.c000066400000000000000000001517221217717257200172620ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions moved from segment.c to make editor separable from game. * */ #include #include #include // for memset() #include "inferno.h" #include "game.h" #include "dxxerror.h" #include "console.h" #include "vecmat.h" #include "gameseg.h" #include "wall.h" #include "fuelcen.h" #include "byteswap.h" #include "mission.h" // How far a point can be from a plane, and still be "in" the plane #define PLANE_DIST_TOLERANCE 250 // ------------------------------------------------------------------------------------------ // Compute the center point of a side of a segment. // The center point is defined to be the average of the 4 points defining the side. void compute_center_point_on_side(vms_vector *vp,segment *sp,int side) { int v; vm_vec_zero(vp); for (v=0; v<4; v++) vm_vec_add2(vp,&Vertices[sp->verts[Side_to_verts[side][v]]]); vm_vec_scale(vp,F1_0/4); } // ------------------------------------------------------------------------------------------ // Compute segment center. // The center point is defined to be the average of the 8 points defining the segment. void compute_segment_center(vms_vector *vp,segment *sp) { int v; vm_vec_zero(vp); for (v=0; v<8; v++) vm_vec_add2(vp,&Vertices[sp->verts[v]]); vm_vec_scale(vp,F1_0/8); } // ----------------------------------------------------------------------------- // Given two segments, return the side index in the connecting segment which connects to the base segment // Optimized by MK on 4/21/94 because it is a 2% load. int find_connect_side(segment *base_seg, segment *con_seg) { int s; short base_seg_num = base_seg - Segments; short *childs = con_seg->children; for (s=0; stype) { case SIDE_IS_QUAD: return 1; break; case SIDE_IS_TRI_02: case SIDE_IS_TRI_13: return 2; break; default: Error("Illegal type = %i\n", sidep->type); return 0; break; } } // Fill in array with four absolute point numbers for a given side void get_side_verts(int *vertlist,int segnum,int sidenum) { int i; sbyte *sv = Side_to_verts[sidenum]; int *vp = Segments[segnum].verts; for (i=4; i--;) vertlist[i] = vp[sv[i]]; } #ifdef EDITOR // ----------------------------------------------------------------------------------- // Create all vertex lists (1 or 2) for faces on a side. // Sets: // num_faces number of lists // vertices vertices in all (1 or 2) faces // If there is one face, it has 4 vertices. // If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2, // face #1 is stored in vertices 3,4,5. // Note: these are not absolute vertex numbers, but are relative to the segment // Note: for triagulated sides, the middle vertex of each trianle is the one NOT // adjacent on the diagonal edge void create_all_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum) { side *sidep = &Segments[segnum].sides[sidenum]; int *sv = Side_to_verts_int[sidenum]; Assert((segnum <= Highest_segment_index) && (segnum >= 0)); Assert((sidenum >= 0) && (sidenum < 6)); switch (sidep->type) { case SIDE_IS_QUAD: vertices[0] = sv[0]; vertices[1] = sv[1]; vertices[2] = sv[2]; vertices[3] = sv[3]; *num_faces = 1; break; case SIDE_IS_TRI_02: *num_faces = 2; vertices[0] = sv[0]; vertices[1] = sv[1]; vertices[2] = sv[2]; vertices[3] = sv[2]; vertices[4] = sv[3]; vertices[5] = sv[0]; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS() //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; case SIDE_IS_TRI_13: *num_faces = 2; vertices[0] = sv[3]; vertices[1] = sv[0]; vertices[2] = sv[1]; vertices[3] = sv[1]; vertices[4] = sv[2]; vertices[5] = sv[3]; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS() //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; default: Error("Illegal side type (1), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum); break; } } #endif // ----------------------------------------------------------------------------------- // Like create all vertex lists, but returns the vertnums (relative to // the side) for each of the faces that make up the side. // If there is one face, it has 4 vertices. // If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2, // face #1 is stored in vertices 3,4,5. void create_all_vertnum_lists(int *num_faces, int *vertnums, int segnum, int sidenum) { side *sidep = &Segments[segnum].sides[sidenum]; Assert((segnum <= Highest_segment_index) && (segnum >= 0)); switch (sidep->type) { case SIDE_IS_QUAD: vertnums[0] = 0; vertnums[1] = 1; vertnums[2] = 2; vertnums[3] = 3; *num_faces = 1; break; case SIDE_IS_TRI_02: *num_faces = 2; vertnums[0] = 0; vertnums[1] = 1; vertnums[2] = 2; vertnums[3] = 2; vertnums[4] = 3; vertnums[5] = 0; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS() //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; case SIDE_IS_TRI_13: *num_faces = 2; vertnums[0] = 3; vertnums[1] = 0; vertnums[2] = 1; vertnums[3] = 1; vertnums[4] = 2; vertnums[5] = 3; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS() //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; default: Error("Illegal side type (2), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum); break; } } // ----- // like create_all_vertex_lists(), but generate absolute point numbers void create_abs_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum, const char *calling_file, int calling_linenum) { int *vp = Segments[segnum].verts; side *sidep = &Segments[segnum].sides[sidenum]; int *sv = Side_to_verts_int[sidenum]; Assert((segnum <= Highest_segment_index) && (segnum >= 0)); switch (sidep->type) { case SIDE_IS_QUAD: vertices[0] = vp[sv[0]]; vertices[1] = vp[sv[1]]; vertices[2] = vp[sv[2]]; vertices[3] = vp[sv[3]]; *num_faces = 1; break; case SIDE_IS_TRI_02: *num_faces = 2; vertices[0] = vp[sv[0]]; vertices[1] = vp[sv[1]]; vertices[2] = vp[sv[2]]; vertices[3] = vp[sv[2]]; vertices[4] = vp[sv[3]]; vertices[5] = vp[sv[0]]; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS(), //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; case SIDE_IS_TRI_13: *num_faces = 2; vertices[0] = vp[sv[3]]; vertices[1] = vp[sv[0]]; vertices[2] = vp[sv[1]]; vertices[3] = vp[sv[1]]; vertices[4] = vp[sv[2]]; vertices[5] = vp[sv[3]]; //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS() //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS() break; default: Error("Illegal side type (3), type = %i, segment # = %i, side # = %i caller:%s:%i\n Please report this bug.\n", sidep->type, segnum, sidenum ,calling_file,calling_linenum); break; } } //returns 3 different bitmasks with info telling if this sphere is in //this segment. See segmasks structure for info on fields segmasks get_seg_masks(const vms_vector *checkp, int segnum, fix rad, const char *calling_file, int calling_linenum) { int sn,facebit,sidebit; segmasks masks; int num_faces; int vertex_list[6]; segment *seg; extern int Current_level_num; if (segnum < 0 || segnum > Highest_segment_index) Error("segnum == %i (%i) in get_seg_masks() \ncheckp: %i,%i,%i, rad: %i \nfrom file: %s, line: %i \nMission: %s (%i) \nPlease report this bug.\n",segnum,Highest_segment_index,checkp->x,checkp->y,checkp->z,rad,calling_file,calling_linenum, Current_mission_filename, Current_level_num); Assert((segnum <= Highest_segment_index) && (segnum >= 0)); seg = &Segments[segnum]; //check point against each side of segment. return bitmask masks.sidemask = masks.facemask = masks.centermask = 0; for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) { #ifndef COMPACT_SEGS side *s = &seg->sides[sn]; #endif int side_pokes_out; int vertnum,fn; // Get number of faces on this side, and at vertex_list, store vertices. // If one face, then vertex_list indicates a quadrilateral. // If two faces, then 0,1,2 define one triangle, 3,4,5 define the second. create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, calling_file, calling_linenum); //ok...this is important. If a side has 2 faces, we need to know if //those faces form a concave or convex side. If the side pokes out, //then a point is on the back of the side if it is behind BOTH faces, //but if the side pokes in, a point is on the back if behind EITHER face. if (num_faces==2) { fix dist; int side_count,center_count; #ifdef COMPACT_SEGS vms_vector normals[2]; #endif vertnum = min(vertex_list[0],vertex_list[2]); #ifdef COMPACT_SEGS get_side_normals(seg, sn, &normals[0], &normals[1] ); #endif if (vertex_list[4] < vertex_list[1]) #ifdef COMPACT_SEGS dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]); #else dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]); #endif else #ifdef COMPACT_SEGS dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]); #else dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]); #endif side_pokes_out = (dist > PLANE_DIST_TOLERANCE); side_count = center_count = 0; for (fn=0;fn<2;fn++,facebit<<=1) { #ifdef COMPACT_SEGS dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]); #else dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]); #endif if (dist < -PLANE_DIST_TOLERANCE) //in front of face center_count++; if (dist-rad < -PLANE_DIST_TOLERANCE) { masks.facemask |= facebit; side_count++; } } if (!side_pokes_out) { //must be behind both faces if (side_count==2) masks.sidemask |= sidebit; if (center_count==2) masks.centermask |= sidebit; } else { //must be behind at least one face if (side_count) masks.sidemask |= sidebit; if (center_count) masks.centermask |= sidebit; } } else { //only one face on this side fix dist; int i; #ifdef COMPACT_SEGS vms_vector normal; #endif //use lowest point number vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS get_side_normal(seg, sn, 0, &normal ); dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]); #else dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]); #endif if (dist < -PLANE_DIST_TOLERANCE) masks.centermask |= sidebit; if (dist-rad < -PLANE_DIST_TOLERANCE) { masks.facemask |= facebit; masks.sidemask |= sidebit; } facebit <<= 2; } } return masks; } //this was converted from get_seg_masks()...it fills in an array of 6 //elements for the distace behind each side, or zero if not behind //only gets centermask, and assumes zero rad ubyte get_side_dists(vms_vector *checkp,int segnum,fix *side_dists) { int sn,facebit,sidebit; ubyte mask; int num_faces; int vertex_list[6]; segment *seg; Assert((segnum <= Highest_segment_index) && (segnum >= 0)); seg = &Segments[segnum]; //check point against each side of segment. return bitmask mask = 0; for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) { #ifndef COMPACT_SEGS side *s = &seg->sides[sn]; #endif int side_pokes_out; int fn; side_dists[sn] = 0; // Get number of faces on this side, and at vertex_list, store vertices. // If one face, then vertex_list indicates a quadrilateral. // If two faces, then 0,1,2 define one triangle, 3,4,5 define the second. create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, __FILE__, __LINE__); //ok...this is important. If a side has 2 faces, we need to know if //those faces form a concave or convex side. If the side pokes out, //then a point is on the back of the side if it is behind BOTH faces, //but if the side pokes in, a point is on the back if behind EITHER face. if (num_faces==2) { fix dist; int center_count; int vertnum; #ifdef COMPACT_SEGS vms_vector normals[2]; #endif vertnum = min(vertex_list[0],vertex_list[2]); #ifdef COMPACT_SEGS get_side_normals(seg, sn, &normals[0], &normals[1] ); #endif if (vertex_list[4] < vertex_list[1]) #ifdef COMPACT_SEGS dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]); #else dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]); #endif else #ifdef COMPACT_SEGS dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]); #else dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]); #endif side_pokes_out = (dist > PLANE_DIST_TOLERANCE); center_count = 0; for (fn=0;fn<2;fn++,facebit<<=1) { #ifdef COMPACT_SEGS dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]); #else dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]); #endif if (dist < -PLANE_DIST_TOLERANCE) { //in front of face center_count++; side_dists[sn] += dist; } } if (!side_pokes_out) { //must be behind both faces if (center_count==2) { mask |= sidebit; side_dists[sn] /= 2; //get average } } else { //must be behind at least one face if (center_count) { mask |= sidebit; if (center_count==2) side_dists[sn] /= 2; //get average } } } else { //only one face on this side fix dist; int i,vertnum; #ifdef COMPACT_SEGS vms_vector normal; #endif //use lowest point number vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS get_side_normal(seg, sn, 0, &normal ); dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]); #else dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]); #endif if (dist < -PLANE_DIST_TOLERANCE) { mask |= sidebit; side_dists[sn] = dist; } facebit <<= 2; } } return mask; } #if !defined(NDEBUG) || defined(EDITOR) #ifndef COMPACT_SEGS //returns true if errors detected int check_norms(int segnum,int sidenum,int facenum,int csegnum,int csidenum,int cfacenum) { vms_vector *n0,*n1; n0 = &Segments[segnum].sides[sidenum].normals[facenum]; n1 = &Segments[csegnum].sides[csidenum].normals[cfacenum]; if (n0->x != -n1->x || n0->y != -n1->y || n0->z != -n1->z) { return 1; } else return 0; } //heavy-duty error checking int check_segment_connections(void) { int segnum,sidenum; int errors=0; for (segnum=0;segnum<=Highest_segment_index;segnum++) { segment *seg; seg = &Segments[segnum]; for (sidenum=0;sidenum<6;sidenum++) { segment *cseg; int num_faces,csegnum,csidenum,con_num_faces; int vertex_list[6],con_vertex_list[6]; create_abs_vertex_lists(&num_faces, vertex_list, segnum, sidenum, __FILE__, __LINE__); csegnum = seg->children[sidenum]; if (csegnum >= 0) { cseg = &Segments[csegnum]; csidenum = find_connect_side(seg,cseg); if (csidenum == -1) { errors = 1; continue; } create_abs_vertex_lists(&con_num_faces, con_vertex_list, csegnum, csidenum, __FILE__, __LINE__); if (con_num_faces != num_faces) { errors = 1; } else if (num_faces == 1) { int t; for (t=0;t<4 && con_vertex_list[t]!=vertex_list[0];t++); if (t==4 || vertex_list[0] != con_vertex_list[t] || vertex_list[1] != con_vertex_list[(t+3)%4] || vertex_list[2] != con_vertex_list[(t+2)%4] || vertex_list[3] != con_vertex_list[(t+1)%4]) { errors = 1; } else errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0); } else { if (vertex_list[1] == con_vertex_list[1]) { if (vertex_list[4] != con_vertex_list[4] || vertex_list[0] != con_vertex_list[2] || vertex_list[2] != con_vertex_list[0] || vertex_list[3] != con_vertex_list[5] || vertex_list[5] != con_vertex_list[3]) { Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type; } else { errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0); errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,1); } } else { if (vertex_list[1] != con_vertex_list[4] || vertex_list[4] != con_vertex_list[1] || vertex_list[0] != con_vertex_list[5] || vertex_list[5] != con_vertex_list[0] || vertex_list[2] != con_vertex_list[3] || vertex_list[3] != con_vertex_list[2]) { Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type; } else { errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,1); errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,0); } } } } } } return errors; } #endif #endif #ifdef EDITOR int Doing_lighting_hack_flag=0; #else #define Doing_lighting_hack_flag 0 #endif // figure out what seg the given point is in, tracing through segments // returns segment number, or -1 if can't find segment int trace_segs(vms_vector *p0, int oldsegnum, int recursion_count) { int centermask; segment *seg; fix side_dists[6]; fix biggest_val; int sidenum, bit, check, biggest_side; static ubyte visited [MAX_SEGMENTS]; Assert((oldsegnum <= Highest_segment_index) && (oldsegnum >= 0)); if (recursion_count >= Num_segments) { con_printf (CON_DEBUG, "trace_segs: Segment not found\n"); return -1; } if (recursion_count == 0) memset (visited, 0, sizeof (visited)); if (visited [oldsegnum]) return -1; visited [oldsegnum] = 1; centermask = get_side_dists(p0,oldsegnum,side_dists); //check old segment if (centermask == 0) // we are in the old segment return oldsegnum; //..say so for (;;) { seg = &Segments[oldsegnum]; biggest_side = -1; biggest_val = 0; for (sidenum = 0, bit = 1; sidenum < 6; sidenum++, bit <<= 1) if ((centermask & bit) && (seg->children[sidenum] > -1) && side_dists[sidenum] < biggest_val) { biggest_val = side_dists[sidenum]; biggest_side = sidenum; } if (biggest_side == -1) break; side_dists[biggest_side] = 0; // trace into adjacent segment: check = trace_segs(p0, seg->children[biggest_side], recursion_count + 1); if (check >= 0) //we've found a segment return check; } return -1; //we haven't found a segment } int Exhaustive_count=0, Exhaustive_failed_count=0; //Tries to find a segment for a point, in the following way: // 1. Check the given segment // 2. Recursively trace through attached segments // 3. Check all the segmentns //Returns segnum if found, or -1 int find_point_seg(vms_vector *p,int segnum) { int newseg; //allow segnum==-1, meaning we have no idea what segment point is in Assert((segnum <= Highest_segment_index) && (segnum >= -1)); if (segnum != -1) { newseg = trace_segs(p, segnum, 0); if (newseg != -1) //we found a segment! return newseg; } //couldn't find via attached segs, so search all segs // MK: 10/15/94 // This Doing_lighting_hack_flag thing added by mk because the hundreds of scrolling messages were // slowing down lighting, and in about 98% of cases, it would just return -1 anyway. // Matt: This really should be fixed, though. We're probably screwing up our lighting in a few places. if (!Doing_lighting_hack_flag) { for (newseg=0;newseg <= Highest_segment_index;newseg++) if (get_seg_masks(p, newseg, 0, __FILE__, __LINE__).centermask == 0) return newseg; return -1; //no segment found } else return -1; } //--repair-- // ------------------------------------------------------------------------------ //--repair-- void clsd_repair_center(int segnum) //--repair-- { //--repair-- int sidenum; //--repair-- //--repair-- // --- Set repair center bit for all repair center segments. //--repair-- if (Segments[segnum].special == SEGMENT_IS_REPAIRCEN) { //--repair-- Lsegments[segnum].special_type |= SS_REPAIR_CENTER; //--repair-- Lsegments[segnum].special_segment = segnum; //--repair-- } //--repair-- //--repair-- // --- Set repair center bit for all segments adjacent to a repair center. //--repair-- for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { //--repair-- int s = Segments[segnum].children[sidenum]; //--repair-- //--repair-- if ( (s != -1) && (Segments[s].special==SEGMENT_IS_REPAIRCEN) ) { //--repair-- Lsegments[segnum].special_type |= SS_REPAIR_CENTER; //--repair-- Lsegments[segnum].special_segment = s; //--repair-- } //--repair-- } //--repair-- } //--repair-- // ------------------------------------------------------------------------------ //--repair-- // --- Set destination points for all Materialization centers. //--repair-- void clsd_materialization_center(int segnum) //--repair-- { //--repair-- if (Segments[segnum].special == SEGMENT_IS_ROBOTMAKER) { //--repair-- //--repair-- } //--repair-- } //--repair-- //--repair-- int Lsegment_highest_segment_index, Lsegment_highest_vertex_index; //--repair-- //--repair-- // ------------------------------------------------------------------------------ //--repair-- // Create data specific to mine which doesn't get written to disk. //--repair-- // Highest_segment_index and Highest_object_index must be valid. //--repair-- // 07/21: set repair center bit //--repair-- void create_local_segment_data(void) //--repair-- { //--repair-- int segnum; //--repair-- //--repair-- // --- Initialize all Lsegments. //--repair-- for (segnum=0; segnum <= Highest_segment_index; segnum++) { //--repair-- Lsegments[segnum].special_type = 0; //--repair-- Lsegments[segnum].special_segment = -1; //--repair-- } //--repair-- //--repair-- for (segnum=0; segnum <= Highest_segment_index; segnum++) { //--repair-- //--repair-- clsd_repair_center(segnum); //--repair-- clsd_materialization_center(segnum); //--repair-- //--repair-- } //--repair-- //--repair-- // Set check variables. //--repair-- // In main game loop, make sure these are valid, else Lsegments is not valid. //--repair-- Lsegment_highest_segment_index = Highest_segment_index; //--repair-- Lsegment_highest_vertex_index = Highest_vertex_index; //--repair-- } //--repair-- //--repair-- // ------------------------------------------------------------------------------------------ //--repair-- // Sort of makes sure create_local_segment_data has been called for the currently executing mine. //--repair-- // It is not failsafe, as you will see if you look at the code. //--repair-- // Returns 1 if Lsegments appears valid, 0 if not. //--repair-- int check_lsegments_validity(void) //--repair-- { //--repair-- return ((Lsegment_highest_segment_index == Highest_segment_index) && (Lsegment_highest_vertex_index == Highest_vertex_index)); //--repair-- } #define MAX_LOC_POINT_SEGS 64 int Connected_segment_distance; // ---------------------------------------------------------------------------------------------------------- // Determine whether seg0 and seg1 are reachable in a way that allows sound to pass. // Search up to a maximum depth of max_depth. // Return the distance. fix find_connected_distance(vms_vector *p0, int seg0, vms_vector *p1, int seg1, int max_depth, int wid_flag) { int cur_seg; int sidenum; int qtail = 0, qhead = 0; int i; sbyte visited[MAX_SEGMENTS]; seg_seg seg_queue[MAX_SEGMENTS]; short depth[MAX_SEGMENTS]; int cur_depth; int num_points; point_seg point_segs[MAX_LOC_POINT_SEGS]; fix dist; // If > this, will overrun point_segs buffer if (max_depth > MAX_LOC_POINT_SEGS-2) { max_depth = MAX_LOC_POINT_SEGS-2; } if (seg0 == seg1) { Connected_segment_distance = 0; return vm_vec_dist_quick(p0, p1); } else if (find_connect_side(&Segments[seg0], &Segments[seg1]) != -1) { Connected_segment_distance = 1; return vm_vec_dist_quick(p0, p1); } num_points = 0; // for (i=0; i<=Highest_segment_index; i++) { // visited[i] = 0; // depth[i] = 0; // } memset(visited, 0, Highest_segment_index+1); memset(depth, 0, Highest_segment_index+1); cur_seg = seg0; visited[cur_seg] = 1; cur_depth = 0; while (cur_seg != seg1) { segment *segp = &Segments[cur_seg]; for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { int snum = sidenum; if (WALL_IS_DOORWAY(segp, snum) & wid_flag) { int this_seg = segp->children[snum]; if (!visited[this_seg]) { seg_queue[qtail].start = cur_seg; seg_queue[qtail].end = this_seg; visited[this_seg] = 1; depth[qtail++] = cur_depth+1; if (max_depth != -1) { if (depth[qtail-1] == max_depth) { Connected_segment_distance = 1000; return -1; // seg1 = seg_queue[qtail-1].end; // goto fcd_done1; } } else if (this_seg == seg1) { goto fcd_done1; } } } } // for (sidenum... if (qhead >= qtail) { Connected_segment_distance = 1000; return -1; } cur_seg = seg_queue[qhead].end; cur_depth = depth[qhead]; qhead++; fcd_done1: ; } // while (cur_seg ... // Set qtail to the segment which ends at the goal. while (seg_queue[--qtail].end != seg1) if (qtail < 0) { Connected_segment_distance = 1000; return -1; } while (qtail >= 0) { int parent_seg, this_seg; this_seg = seg_queue[qtail].end; parent_seg = seg_queue[qtail].start; point_segs[num_points].segnum = this_seg; compute_segment_center(&point_segs[num_points].point,&Segments[this_seg]); num_points++; if (parent_seg == seg0) break; while (seg_queue[--qtail].end != parent_seg) Assert(qtail >= 0); } point_segs[num_points].segnum = seg0; compute_segment_center(&point_segs[num_points].point,&Segments[seg0]); num_points++; // Compute distance if (num_points == 1) { Connected_segment_distance = num_points; return vm_vec_dist_quick(p0, p1); } else { dist = vm_vec_dist_quick(p1, &point_segs[1].point); dist += vm_vec_dist_quick(p0, &point_segs[num_points-2].point); for (i=1; i= 0x00010000) return MATRIX_MAX; else if (f <= -0x00010000) return -MATRIX_MAX; else return f >> MATRIX_PRECISION; } #define VEL_PRECISION 12 // Create a shortpos struct from an object. // Extract the matrix into byte values. // Create a position relative to vertex 0 with 1/256 normal "fix" precision. // Stuff segment in a short. void create_shortpos(shortpos *spp, object *objp, int swap_bytes) { // int segnum; sbyte *sp; sp = spp->bytemat; *sp++ = convert_to_byte(objp->orient.rvec.x); *sp++ = convert_to_byte(objp->orient.uvec.x); *sp++ = convert_to_byte(objp->orient.fvec.x); *sp++ = convert_to_byte(objp->orient.rvec.y); *sp++ = convert_to_byte(objp->orient.uvec.y); *sp++ = convert_to_byte(objp->orient.fvec.y); *sp++ = convert_to_byte(objp->orient.rvec.z); *sp++ = convert_to_byte(objp->orient.uvec.z); *sp++ = convert_to_byte(objp->orient.fvec.z); spp->xo = (objp->pos.x - Vertices[Segments[objp->segnum].verts[0]].x) >> RELPOS_PRECISION; spp->yo = (objp->pos.y - Vertices[Segments[objp->segnum].verts[0]].y) >> RELPOS_PRECISION; spp->zo = (objp->pos.z - Vertices[Segments[objp->segnum].verts[0]].z) >> RELPOS_PRECISION; spp->segment = objp->segnum; spp->velx = (objp->mtype.phys_info.velocity.x) >> VEL_PRECISION; spp->vely = (objp->mtype.phys_info.velocity.y) >> VEL_PRECISION; spp->velz = (objp->mtype.phys_info.velocity.z) >> VEL_PRECISION; // swap the short values for the big-endian machines. if (swap_bytes) { spp->xo = INTEL_SHORT(spp->xo); spp->yo = INTEL_SHORT(spp->yo); spp->zo = INTEL_SHORT(spp->zo); spp->segment = INTEL_SHORT(spp->segment); spp->velx = INTEL_SHORT(spp->velx); spp->vely = INTEL_SHORT(spp->vely); spp->velz = INTEL_SHORT(spp->velz); } } void extract_shortpos(object *objp, shortpos *spp, int swap_bytes) { int segnum; sbyte *sp; sp = spp->bytemat; objp->orient.rvec.x = *sp++ << MATRIX_PRECISION; objp->orient.uvec.x = *sp++ << MATRIX_PRECISION; objp->orient.fvec.x = *sp++ << MATRIX_PRECISION; objp->orient.rvec.y = *sp++ << MATRIX_PRECISION; objp->orient.uvec.y = *sp++ << MATRIX_PRECISION; objp->orient.fvec.y = *sp++ << MATRIX_PRECISION; objp->orient.rvec.z = *sp++ << MATRIX_PRECISION; objp->orient.uvec.z = *sp++ << MATRIX_PRECISION; objp->orient.fvec.z = *sp++ << MATRIX_PRECISION; if (swap_bytes) { spp->xo = INTEL_SHORT(spp->xo); spp->yo = INTEL_SHORT(spp->yo); spp->zo = INTEL_SHORT(spp->zo); spp->segment = INTEL_SHORT(spp->segment); spp->velx = INTEL_SHORT(spp->velx); spp->vely = INTEL_SHORT(spp->vely); spp->velz = INTEL_SHORT(spp->velz); } segnum = spp->segment; Assert((segnum >= 0) && (segnum <= Highest_segment_index)); objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x; objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y; objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z; objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION); objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION); objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION); obj_relink(objp-Objects, segnum); } // create and extract quaternion structure from object data which greatly saves bytes by using quaternion instead or orientation matrix void create_quaternionpos(quaternionpos * qpp, object * objp, int swap_bytes) { vms_quaternion_from_matrix(&qpp->orient, &objp->orient); qpp->pos = objp->pos; qpp->vel = objp->mtype.phys_info.velocity; qpp->rotvel = objp->mtype.phys_info.rotvel; if (swap_bytes) { qpp->orient.w = INTEL_SHORT(qpp->orient.w); qpp->orient.x = INTEL_SHORT(qpp->orient.x); qpp->orient.y = INTEL_SHORT(qpp->orient.y); qpp->orient.z = INTEL_SHORT(qpp->orient.z); qpp->pos.x = INTEL_INT(qpp->pos.x); qpp->pos.y = INTEL_INT(qpp->pos.y); qpp->pos.z = INTEL_INT(qpp->pos.z); qpp->vel.x = INTEL_INT(qpp->vel.x); qpp->vel.y = INTEL_INT(qpp->vel.y); qpp->vel.z = INTEL_INT(qpp->vel.z); qpp->rotvel.x = INTEL_INT(qpp->rotvel.x); qpp->rotvel.y = INTEL_INT(qpp->rotvel.y); qpp->rotvel.z = INTEL_INT(qpp->rotvel.z); } } void extract_quaternionpos(object *objp, quaternionpos *qpp, int swap_bytes) { if (swap_bytes) { qpp->orient.w = INTEL_SHORT(qpp->orient.w); qpp->orient.x = INTEL_SHORT(qpp->orient.x); qpp->orient.y = INTEL_SHORT(qpp->orient.y); qpp->orient.z = INTEL_SHORT(qpp->orient.z); qpp->pos.x = INTEL_INT(qpp->pos.x); qpp->pos.y = INTEL_INT(qpp->pos.y); qpp->pos.z = INTEL_INT(qpp->pos.z); qpp->vel.x = INTEL_INT(qpp->vel.x); qpp->vel.y = INTEL_INT(qpp->vel.y); qpp->vel.z = INTEL_INT(qpp->vel.z); qpp->rotvel.x = INTEL_INT(qpp->rotvel.x); qpp->rotvel.y = INTEL_INT(qpp->rotvel.y); qpp->rotvel.z = INTEL_INT(qpp->rotvel.z); } vms_matrix_from_quaternion(&objp->orient, &qpp->orient); objp->pos = qpp->pos; objp->mtype.phys_info.velocity = qpp->vel; objp->mtype.phys_info.rotvel = qpp->rotvel; update_object_seg(objp); } // ----------------------------------------------------------------------------- // Segment validation functions. // Moved from editor to game so we can compute surface normals at load time. // ------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------ // Extract a vector from a segment. The vector goes from the start face to the end face. // The point on each face is the average of the four points forming the face. void extract_vector_from_segment(segment *sp, vms_vector *vp, int start, int end) { int i; vms_vector vs,ve; vm_vec_zero(&vs); vm_vec_zero(&ve); for (i=0; i<4; i++) { vm_vec_add2(&vs,&Vertices[sp->verts[Side_to_verts[start][i]]]); vm_vec_add2(&ve,&Vertices[sp->verts[Side_to_verts[end][i]]]); } vm_vec_sub(vp,&ve,&vs); vm_vec_scale(vp,F1_0/4); } //create a matrix that describes the orientation of the given segment void extract_orient_from_segment(vms_matrix *m,segment *seg) { vms_vector fvec,uvec; extract_vector_from_segment(seg,&fvec,WFRONT,WBACK); extract_vector_from_segment(seg,&uvec,WBOTTOM,WTOP); //vector to matrix does normalizations and orthogonalizations vm_vector_2_matrix(m,&fvec,&uvec,NULL); } // ------------------------------------------------------------------------------------------ // Extract the forward vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the front face of the segment // to the center of the back face of the segment. void extract_forward_vector_from_segment(segment *sp,vms_vector *vp) { extract_vector_from_segment(sp,vp,WFRONT,WBACK); } // ------------------------------------------------------------------------------------------ // Extract the right vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the left face of the segment // to the center of the right face of the segment. void extract_right_vector_from_segment(segment *sp,vms_vector *vp) { extract_vector_from_segment(sp,vp,WLEFT,WRIGHT); } // ------------------------------------------------------------------------------------------ // Extract the up vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the bottom face of the segment // to the center of the top face of the segment. void extract_up_vector_from_segment(segment *sp,vms_vector *vp) { extract_vector_from_segment(sp,vp,WBOTTOM,WTOP); } // ---- // A side is determined to be degenerate if the cross products of 3 consecutive points does not point outward. int check_for_degenerate_side(segment *sp, int sidenum) { sbyte *vp = Side_to_verts[sidenum]; vms_vector vec1, vec2, cross, vec_to_center; vms_vector segc, sidec; fix dot; int degeneracy_flag = 0; compute_segment_center(&segc, sp); compute_center_point_on_side(&sidec, sp, sidenum); vm_vec_sub(&vec_to_center, &segc, &sidec); //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]); //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]); //vm_vec_normalize(&vec1); //vm_vec_normalize(&vec2); vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[1]]], &Vertices[sp->verts[(int) vp[0]]]); vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]); vm_vec_cross(&cross, &vec1, &vec2); dot = vm_vec_dot(&vec_to_center, &cross); if (dot <= 0) degeneracy_flag |= 1; //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]); //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]); //vm_vec_normalize(&vec1); //vm_vec_normalize(&vec2); vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]); vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[3]]], &Vertices[sp->verts[(int) vp[2]]]); vm_vec_cross(&cross, &vec1, &vec2); dot = vm_vec_dot(&vec_to_center, &cross); if (dot <= 0) degeneracy_flag |= 1; return degeneracy_flag; } extern int Degenerate_segment_found; // ---- // See if a segment has gotten turned inside out, or something. // If so, set global Degenerate_segment_found and return 1, else return 0. int check_for_degenerate_segment(segment *sp) { vms_vector fvec, rvec, uvec, cross; fix dot; int i, degeneracy_flag = 0; // degeneracy flag for current segment extract_forward_vector_from_segment(sp, &fvec); extract_right_vector_from_segment(sp, &rvec); extract_up_vector_from_segment(sp, &uvec); vm_vec_normalize(&fvec); vm_vec_normalize(&rvec); vm_vec_normalize(&uvec); vm_vec_cross(&cross, &fvec, &rvec); dot = vm_vec_dot(&cross, &uvec); if (dot > 0) degeneracy_flag = 0; else { degeneracy_flag = 1; } // Now, see if degenerate because of any side. for (i=0; isides[sidenum]; sidep->type = SIDE_IS_QUAD; #ifdef COMPACT_SEGS normal = normal; //avoid compiler warning #else sidep->normals[0] = *normal; sidep->normals[1] = *normal; #endif // If there is a connection here, we only formed the faces for the purpose of determining segment boundaries, // so don't generate polys, else they will get rendered. // if (sp->children[sidenum] != -1) // sidep->render_flag = 0; // else // sidep->render_flag = 1; } // ------------------------------------------------------------------------------- // Return v0, v1, v2 = 3 vertices with smallest numbers. If *negate_flag set, then negate normal after computation. // Note, you cannot just compute the normal by treating the points in the opposite direction as this introduces // small differences between normals which should merely be opposites of each other. void get_verts_for_normal(int va, int vb, int vc, int vd, int *v0, int *v1, int *v2, int *v3, int *negate_flag) { int i,j; int v[4],w[4]; // w is a list that shows how things got scrambled so we know if our normal is pointing backwards for (i=0; i<4; i++) w[i] = i; v[0] = va; v[1] = vb; v[2] = vc; v[3] = vd; for (i=1; i<4; i++) for (j=0; j v[i]) { int t; t = v[j]; v[j] = v[i]; v[i] = t; t = w[j]; w[j] = w[i]; w[i] = t; } Assert((v[0] < v[1]) && (v[1] < v[2]) && (v[2] < v[3])); // Now, if for any w[i] & w[i+1]: w[i+1] = (w[i]+3)%4, then must swap *v0 = v[0]; *v1 = v[1]; *v2 = v[2]; *v3 = v[3]; if ( (((w[0]+3) % 4) == w[1]) || (((w[1]+3) % 4) == w[2])) *negate_flag = 1; else *negate_flag = 0; } // ------------------------------------------------------------------------------- void add_side_as_2_triangles(segment *sp, int sidenum) { vms_vector norm; sbyte *vs = Side_to_verts[sidenum]; fix dot; vms_vector vec_13; // vector from vertex 1 to vertex 3 side *sidep = &sp->sides[sidenum]; // Choose how to triangulate. // If a wall, then // Always triangulate so segment is convex. // Use Matt's formula: Na . AD > 0, where ABCD are vertices on side, a is face formed by A,B,C, Na is normal from face a. // If not a wall, then triangulate so whatever is on the other side is triangulated the same (ie, between the same absoluate vertices) if (!IS_CHILD(sp->children[sidenum])) { vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]); vm_vec_sub(&vec_13, &Vertices[sp->verts[vs[3]]], &Vertices[sp->verts[vs[1]]]); dot = vm_vec_dot(&norm, &vec_13); // Now, signifiy whether to triangulate from 0:2 or 1:3 if (dot >= 0) sidep->type = SIDE_IS_TRI_02; else sidep->type = SIDE_IS_TRI_13; #ifndef COMPACT_SEGS // Now, based on triangulation type, set the normals. if (sidep->type == SIDE_IS_TRI_02) { vm_vec_normal(&norm, &Vertices[sp->verts[(int)vs[0]]], &Vertices[sp->verts[(int)vs[1]]], &Vertices[sp->verts[(int)vs[2]]]); sidep->normals[0] = norm; vm_vec_normal(&norm, &Vertices[sp->verts[(int)vs[0]]], &Vertices[sp->verts[(int)vs[2]]], &Vertices[sp->verts[(int)vs[3]]]); sidep->normals[1] = norm; } else { vm_vec_normal(&norm, &Vertices[sp->verts[(int)vs[0]]], &Vertices[sp->verts[(int)vs[1]]], &Vertices[sp->verts[(int)vs[3]]]); sidep->normals[0] = norm; vm_vec_normal(&norm, &Vertices[sp->verts[(int)vs[1]]], &Vertices[sp->verts[(int)vs[2]]], &Vertices[sp->verts[(int)vs[3]]]); sidep->normals[1] = norm; } #endif } else { int i,v[4], vsorted[4]; int negate_flag; for (i=0; i<4; i++) v[i] = sp->verts[vs[i]]; get_verts_for_normal(v[0], v[1], v[2], v[3], &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag); if ((vsorted[0] == v[0]) || (vsorted[0] == v[2])) { sidep->type = SIDE_IS_TRI_02; #ifndef COMPACT_SEGS // Now, get vertices for normal for each triangle based on triangulation type. get_verts_for_normal(v[0], v[1], v[2], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag); vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]); if (negate_flag) vm_vec_negate(&norm); sidep->normals[0] = norm; get_verts_for_normal(v[0], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag); vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]); if (negate_flag) vm_vec_negate(&norm); sidep->normals[1] = norm; #endif } else { sidep->type = SIDE_IS_TRI_13; #ifndef COMPACT_SEGS // Now, get vertices for normal for each triangle based on triangulation type. get_verts_for_normal(v[0], v[1], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag); vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]); if (negate_flag) vm_vec_negate(&norm); sidep->normals[0] = norm; get_verts_for_normal(v[1], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag); vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]); if (negate_flag) vm_vec_negate(&norm); sidep->normals[1] = norm; #endif } } } int sign(fix v) { if (v > PLANE_DIST_TOLERANCE) return 1; else if (v < -(PLANE_DIST_TOLERANCE+1)) //neg & pos round differently return -1; else return 0; } // ------------------------------------------------------------------------------- void create_walls_on_side(segment *sp, int sidenum) { int vm0, vm1, vm2, vm3, negate_flag; int v0, v1, v2, v3; vms_vector vn; fix dist_to_plane; v0 = sp->verts[Side_to_verts[sidenum][0]]; v1 = sp->verts[Side_to_verts[sidenum][1]]; v2 = sp->verts[Side_to_verts[sidenum][2]]; v3 = sp->verts[Side_to_verts[sidenum][3]]; get_verts_for_normal(v0, v1, v2, v3, &vm0, &vm1, &vm2, &vm3, &negate_flag); vm_vec_normal(&vn, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]); dist_to_plane = abs(vm_dist_to_plane(&Vertices[vm3], &vn, &Vertices[vm0])); if (negate_flag) vm_vec_negate(&vn); if (dist_to_plane <= PLANE_DIST_TOLERANCE) add_side_as_quad(sp, sidenum, &vn); else { add_side_as_2_triangles(sp, sidenum); //this code checks to see if we really should be triangulated, and //de-triangulates if we shouldn't be. { int num_faces; int vertex_list[6]; fix dist0,dist1; int s0,s1; int vertnum; side *s; create_abs_vertex_lists(&num_faces, vertex_list, sp - Segments, sidenum, __FILE__, __LINE__); Assert(num_faces == 2); s = &sp->sides[sidenum]; vertnum = min(vertex_list[0],vertex_list[2]); #ifdef COMPACT_SEGS { vms_vector normals[2]; get_side_normals(sp, sidenum, &normals[0], &normals[1] ); dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]); dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]); } #else dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]); dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]); #endif s0 = sign(dist0); s1 = sign(dist1); if (s0==0 || s1==0 || s0!=s1) { sp->sides[sidenum].type = SIDE_IS_QUAD; //detriangulate! #ifndef COMPACT_SEGS sp->sides[sidenum].normals[0] = vn; sp->sides[sidenum].normals[1] = vn; #endif } } } } #ifdef COMPACT_SEGS //#define CACHE_DEBUG 1 #define MAX_CACHE_NORMALS 128 #define CACHE_MASK 127 typedef struct ncache_element { short segnum; ubyte sidenum; vms_vector normals[2]; } ncache_element; int ncache_initialized = 0; ncache_element ncache[MAX_CACHE_NORMALS]; #ifdef CACHE_DEBUG int ncache_counter = 0; int ncache_hits = 0; int ncache_misses = 0; #endif void ncache_init() { ncache_flush(); ncache_initialized = 1; } void ncache_flush() { int i; for (i=0; i>4; if ( (f1&face_flags)==face_flags ) return i; if ( f1 & 1 ) uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] ); else uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] ); ncache[i].sidenum |= face_flags<<4; return i; } #ifdef CACHE_DEBUG ncache_misses++; #endif switch( face_flags ) { case 1: uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] ); break; case 2: uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] ); break; case 3: uncached_get_side_normals(&Segments[segnum], sidenum, &ncache[i].normals[0], &ncache[i].normals[1] ); break; } ncache[i].segnum = segnum; ncache[i].sidenum = sidenum | (face_flags<<4); return i; } void get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm ) { int i; i = find_ncache_element( sp - Segments, sidenum, 1 << face_num ); *vm = ncache[i].normals[face_num]; if (0) { vms_vector tmp; uncached_get_side_normal(sp, sidenum, face_num, &tmp ); Assert( tmp.x == vm->x ); Assert( tmp.y == vm->y ); Assert( tmp.z == vm->z ); } } void get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 ) { int i; i = find_ncache_element( sp - Segments, sidenum, 3 ); *vm1 = ncache[i].normals[0]; *vm2 = ncache[i].normals[1]; if (0) { vms_vector tmp; uncached_get_side_normal(sp, sidenum, 0, &tmp ); Assert( tmp.x == vm1->x ); Assert( tmp.y == vm1->y ); Assert( tmp.z == vm1->z ); uncached_get_side_normal(sp, sidenum, 1, &tmp ); Assert( tmp.x == vm2->x ); Assert( tmp.y == vm2->y ); Assert( tmp.z == vm2->z ); } } void uncached_get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm ) { int vm0, vm1, vm2, vm3, negate_flag; char *vs = Side_to_verts[sidenum]; switch( sp->sides[sidenum].type ) { case SIDE_IS_QUAD: get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vm0, &vm1, &vm2, &vm3, &negate_flag); vm_vec_normal(vm, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]); if (negate_flag) vm_vec_negate(vm); break; case SIDE_IS_TRI_02: if ( face_num == 0 ) vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]); else vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]); break; case SIDE_IS_TRI_13: if ( face_num == 0 ) vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]); else vm_vec_normal(vm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]); break; } } void uncached_get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 ) { int vvm0, vvm1, vvm2, vvm3, negate_flag; char *vs = Side_to_verts[sidenum]; switch( sp->sides[sidenum].type ) { case SIDE_IS_QUAD: get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vvm0, &vvm1, &vvm2, &vvm3, &negate_flag); vm_vec_normal(vm1, &Vertices[vvm0], &Vertices[vvm1], &Vertices[vvm2]); if (negate_flag) vm_vec_negate(vm1); *vm2 = *vm1; break; case SIDE_IS_TRI_02: vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]); vm_vec_normal(vm2, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]); break; case SIDE_IS_TRI_13: vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]); vm_vec_normal(vm2, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]); break; } } #endif // ------------------------------------------------------------------------------- void validate_removable_wall(segment *sp, int sidenum, int tmap_num) { create_walls_on_side(sp, sidenum); sp->sides[sidenum].tmap_num = tmap_num; // assign_default_uvs_to_side(sp, sidenum); // assign_light_to_side(sp, sidenum); } // ------------------------------------------------------------------------------- // Make a just-modified segment side valid. void validate_segment_side(segment *sp, int sidenum) { if (sp->sides[sidenum].wall_num == -1) create_walls_on_side(sp, sidenum); else // create_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num); validate_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num); // Set render_flag. // If side doesn't have a child, then render wall. If it does have a child, but there is a temporary // wall there, then do render wall. // if (sp->children[sidenum] == -1) // sp->sides[sidenum].render_flag = 1; // else if (sp->sides[sidenum].wall_num != -1) // sp->sides[sidenum].render_flag = 1; // else // sp->sides[sidenum].render_flag = 0; } // ------------------------------------------------------------------------------- // Make a just-modified segment valid. // check all sides to see how many faces they each should have (0,1,2) // create new vector normals void validate_segment(segment *sp) { int side; sp->degenerated = check_for_degenerate_segment(sp); for (side = 0; side < MAX_SIDES_PER_SEGMENT; side++) validate_segment_side(sp, side); // assign_default_uvs_to_segment(sp); } // ------------------------------------------------------------------------------- // Validate all segments. // Highest_segment_index must be set. // For all used segments (number <= Highest_segment_index), segnum field must be != -1. void validate_segment_all(void) { int s; for (s=0; s<=Highest_segment_index; s++) #ifdef EDITOR if (Segments[s].segnum != -1) #endif validate_segment(&Segments[s]); #ifdef EDITOR { for (s=Highest_segment_index+1; s> 15; vm_vec_sub(&vec2, &Vertices[Segments[segnum].verts[vnum]], new_pos); vm_vec_scale(&vec2, d_rand()); // d_rand() always in 0..1/2 vm_vec_add2(new_pos, &vec2); } // ---------------------------------------------------------------------------------------------------------- // Set the segment depth of all segments from start_seg in *segbuf. // Returns maximum depth value. int set_segment_depths(int start_seg, ubyte *segbuf) { int i, curseg; ubyte visited[MAX_SEGMENTS]; int queue[MAX_SEGMENTS]; int head, tail; int depth; int parent_depth=0; depth = 1; head = 0; tail = 0; for (i=0; i<=Highest_segment_index; i++) visited[i] = 0; if (segbuf[start_seg] == 0) return 1; queue[tail++] = start_seg; visited[start_seg] = 1; segbuf[start_seg] = depth++; if (depth == 0) depth = 255; while (head < tail) { curseg = queue[head++]; parent_depth = segbuf[curseg]; for (i=0; ipos, (obj)->segnum, 0, __FILE__, __LINE__).centermask == 0) //Tries to find a segment for a point, in the following way: // 1. Check the given segment // 2. Recursively trace through attached segments // 3. Check all the segmentns //Returns segnum if found, or -1 int find_point_seg(vms_vector *p,int segnum); //--repair-- // Create data specific to segments which does not need to get written to disk. //--repair-- extern void create_local_segment_data(void); // Sort of makes sure create_local_segment_data has been called for the currently executing mine. // Returns 1 if Lsegments appears valid, 0 if not. int check_lsegments_validity(void); // ---------------------------------------------------------------------------------------------------------- // Determine whether seg0 and seg1 are reachable using wid_flag to go through walls. // For example, set to WID_RENDPAST_FLAG to see if sound can get from one segment to the other. // set to WID_FLY_FLAG to see if a robot could fly from one to the other. // Search up to a maximum depth of max_depth. // Return the distance. extern fix find_connected_distance(vms_vector *p0, int seg0, vms_vector *p1, int seg1, int max_depth, int wid_flag); //create a matrix that describes the orientation of the given segment extern void extract_orient_from_segment(vms_matrix *m,segment *seg); // In segment.c // Make a just-modified segment valid. // check all sides to see how many faces they each should have (0,1,2) // create new vector normals extern void validate_segment(segment *sp); extern void validate_segment_all(void); // Extract the forward vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the front face of the segment // to the center of the back face of the segment. extern void extract_forward_vector_from_segment(segment *sp,vms_vector *vp); // Extract the right vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the left face of the segment // to the center of the right face of the segment. extern void extract_right_vector_from_segment(segment *sp,vms_vector *vp); // Extract the up vector from segment *sp, return in *vp. // The forward vector is defined to be the vector from the the center of the bottom face of the segment // to the center of the top face of the segment. extern void extract_up_vector_from_segment(segment *sp,vms_vector *vp); extern void create_walls_on_side(segment *sp, int sidenum); extern void pick_random_point_in_seg(vms_vector *new_pos, int segnum); extern void validate_segment_side(segment *sp, int sidenum); #endif dxx-rebirth-0.58.1-d1x/main/gameseq.c000066400000000000000000001032621217717257200172700ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for EndGame, EndLevel, etc. * */ #include #include #include #include #include #include #ifdef OGL #include "ogl_init.h" #endif #include "inferno.h" #include "game.h" #include "key.h" #include "object.h" #include "physics.h" #include "dxxerror.h" #include "joy.h" #include "iff.h" #include "pcx.h" #include "timer.h" #include "render.h" #include "laser.h" #include "screens.h" #include "textures.h" #include "slew.h" #include "gauges.h" #include "texmap.h" #include "3d.h" #include "effects.h" #include "menu.h" #include "gameseg.h" #include "wall.h" #include "ai.h" #include "hostage.h" #include "fuelcen.h" #include "switch.h" #include "digi.h" #include "gamesave.h" #include "scores.h" #include "u_mem.h" #include "palette.h" #include "morph.h" #include "lighting.h" #include "newdemo.h" #include "titles.h" #include "collide.h" #include "weapon.h" #include "sounds.h" #include "args.h" #include "gameseq.h" #include "gamefont.h" #include "newmenu.h" #include "endlevel.h" #include "playsave.h" #include "ctype.h" #include "multi.h" #include "fireball.h" #include "kconfig.h" #include "config.h" #include "robot.h" #include "automap.h" #include "cntrlcen.h" #include "powerup.h" #include "text.h" #include "piggy.h" #include "texmerge.h" #include "paging.h" #include "mission.h" #include "state.h" #include "songs.h" #ifdef NETWORK #include "multi.h" #endif #include "strutil.h" #ifdef EDITOR #include "editor/editor.h" #endif #include "custom.h" #include "byteswap.h" #include "segment.h" #include "gameseg.h" void init_player_stats_new_ship(ubyte pnum); void copy_defaults_to_robot_all(void); int AdvanceLevel(int secret_flag); void StartLevel(int random); //Current_level_num starts at 1 for the first level //-1,-2,-3 are secret levels //0 means not a real level loaded int Current_level_num=0,Next_level_num; char Current_level_name[LEVEL_NAME_LEN]; // #ifndef SHAREWARE // int Last_level,Last_secret_level; // #endif // Global variables describing the player int N_players=1; // Number of players ( >1 means a net game, eh?) int Player_num=0; // The player number who is on the console. player Players[MAX_PLAYERS]; // Misc player info obj_position Player_init[MAX_PLAYERS]; // Global variables telling what sort of game we have int NumNetPlayerPositions = -1; extern fix ThisLevelTime; // Extern from game.c to fix a bug in the cockpit! extern int last_drawn_cockpit; extern int Last_level_path_created; void HUD_clear_messages(); // From hud.c void verify_console_object() { Assert( Player_num > -1 ); Assert( Players[Player_num].objnum > -1 ); ConsoleObject = &Objects[Players[Player_num].objnum]; Assert( ConsoleObject->id==Player_num ); } int count_number_of_robots() { int robot_count; int i; robot_count = 0; for (i=0;i<=Highest_object_index;i++) { if (Objects[i].type == OBJ_ROBOT) robot_count++; } return robot_count; } int count_number_of_hostages() { int count; int i; count = 0; for (i=0;i<=Highest_object_index;i++) { if (Objects[i].type == OBJ_HOSTAGE) count++; } return count; } void gameseq_init_network_players() { int i,k,j; // Initialize network player start locations and object numbers ConsoleObject = &Objects[0]; k = 0; j = 0; for (i=0;i<=Highest_object_index;i++) { if (( Objects[i].type==OBJ_PLAYER ) || (Objects[i].type == OBJ_GHOST) || (Objects[i].type == OBJ_COOP)) { #ifndef SHAREWARE if ( (!(Game_mode & GM_MULTI_COOP) && ((Objects[i].type == OBJ_PLAYER)||(Objects[i].type==OBJ_GHOST))) || ((Game_mode & GM_MULTI_COOP) && ((j == 0) || ( Objects[i].type==OBJ_COOP ))) ) { Objects[i].type=OBJ_PLAYER; #endif Player_init[k].pos = Objects[i].pos; Player_init[k].orient = Objects[i].orient; Player_init[k].segnum = Objects[i].segnum; Players[k].objnum = i; Objects[i].id = k; k++; #ifndef SHAREWARE } else obj_delete(i); j++; #endif } } NumNetPlayerPositions = k; } void gameseq_remove_unused_players() { int i; // 'Remove' the unused players #ifdef NETWORK if (Game_mode & GM_MULTI) { for (i=0; i < NumNetPlayerPositions; i++) { if ((!Players[i].connected) || (i >= N_players)) { multi_make_player_ghost(i); } } } else #endif { // Note link to above if!!! for (i=1; i < NumNetPlayerPositions; i++) { obj_delete(Players[i].objnum); } } } fix StartingShields=INITIAL_SHIELDS; // Setup player for new game void init_player_stats_game(ubyte pnum) { Players[pnum].score = 0; Players[pnum].last_score = 0; Players[pnum].lives = INITIAL_LIVES; Players[pnum].level = 1; Players[pnum].time_level = 0; Players[pnum].time_total = 0; Players[pnum].hours_level = 0; Players[pnum].hours_total = 0; Players[pnum].killer_objnum = -1; Players[pnum].net_killed_total = 0; Players[pnum].net_kills_total = 0; Players[pnum].num_kills_level = 0; Players[pnum].num_kills_total = 0; Players[pnum].num_robots_level = 0; Players[pnum].num_robots_total = 0; Players[pnum].KillGoalCount = 0; Players[pnum].hostages_rescued_total = 0; Players[pnum].hostages_level = 0; Players[pnum].hostages_total = 0; Players[pnum].laser_level = 0; Players[pnum].flags = 0; init_player_stats_new_ship(pnum); } void init_ammo_and_energy(void) { if (Players[Player_num].energy < INITIAL_ENERGY) Players[Player_num].energy = INITIAL_ENERGY; if (Players[Player_num].shields < StartingShields) Players[Player_num].shields = StartingShields; // for (i=0; iid=Player_num; ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; Game_suspended = 0; verify_console_object(); Control_center_destroyed = 0; if (Newdemo_state != ND_STATE_PLAYBACK) gameseq_remove_unused_players(); init_cockpit(); init_robots_for_level(); init_ai_objects(); init_morphs(); init_all_matcens(); init_player_stats_new_ship(Player_num); if (!Game_wind) Game_wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, game_handler, NULL); } #endif void reset_player_object(); //do whatever needs to be done when a player dies in multiplayer void DoGameOver() { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } //update various information about the player void update_player_stats() { Players[Player_num].time_level += FrameTime; //the never-ending march of time... if ( Players[Player_num].time_level > i2f(3600) ) { Players[Player_num].time_level -= i2f(3600); Players[Player_num].hours_level++; } Players[Player_num].time_total += FrameTime; //the never-ending march of time... if ( Players[Player_num].time_total > i2f(3600) ) { Players[Player_num].time_total -= i2f(3600); Players[Player_num].hours_total++; } } //go through this level and start any eclip sounds void set_sound_sources() { int segnum,sidenum; segment *seg; digi_init_sounds(); //clear old sounds for (seg=&Segments[0],segnum=0;segnum<=Highest_segment_index;seg++,segnum++) for (sidenum=0;sidenumsides[sidenum].tmap_num2) != 0) if ((ec=TmapInfo[tm&0x3fff].eclip_num)!=-1) if ((sn=Effects[ec].sound_num)!=-1) { vms_vector pnt; compute_center_point_on_side(&pnt,seg,sidenum); digi_link_sound_to_pos(sn,segnum,sidenum,&pnt,1, F1_0/2); } } } //fix flash_dist=i2f(1); fix flash_dist=fl2f(.9); //create flash for player appearance void create_player_appearance_effect(object *player_obj) { vms_vector pos; object *effect_obj; #ifndef NDEBUG { int objnum = player_obj-Objects; if ( (objnum < 0) || (objnum > Highest_object_index) ) Int3(); // See Rob, trying to track down weird network bug } #endif if (player_obj == Viewer) vm_vec_scale_add(&pos, &player_obj->pos, &player_obj->orient.fvec, fixmul(player_obj->size,flash_dist)); else pos = player_obj->pos; effect_obj = object_create_explosion(player_obj->segnum, &pos, player_obj->size, VCLIP_PLAYER_APPEARANCE ); if (effect_obj) { effect_obj->orient = player_obj->orient; if ( Vclip[VCLIP_PLAYER_APPEARANCE].sound_num > -1 ) digi_link_sound_to_object( Vclip[VCLIP_PLAYER_APPEARANCE].sound_num, effect_obj-Objects, 0, F1_0); } } // // New Game sequencing functions // extern int descent_critical_error; //get level filename. level numbers start at 1. Secret levels are -1,-2,-3 char *get_level_file(int level_num) { #ifdef SHAREWARE { static char t[13]; sprintf(t, "level%02d.sdl", level_num); return t; } #else if (level_num<0) //secret level return Secret_level_names[-level_num-1]; else //normal level return Level_names[level_num-1]; #endif } // routine to calculate the checksum of the segments. void do_checksum_calc(ubyte *b, int len, unsigned int *s1, unsigned int *s2) { while(len--) { *s1 += *b++; if (*s1 >= 255) *s1 -= 255; *s2 += *s1; } } ushort netmisc_calc_checksum() { int i, j, k; unsigned int sum1,sum2; short s; int t; sum1 = sum2 = 0; for (i = 0; i < Highest_segment_index + 1; i++) { for (j = 0; j < MAX_SIDES_PER_SEGMENT; j++) { do_checksum_calc((unsigned char *)&(Segments[i].sides[j].type), 1, &sum1, &sum2); do_checksum_calc(&(Segments[i].sides[j].pad), 1, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].wall_num); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].tmap_num); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); s = INTEL_SHORT(Segments[i].sides[j].tmap_num2); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); for (k = 0; k < 4; k++) { t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].u)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].v)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].uvls[k].l)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); } for (k = 0; k < 2; k++) { t = INTEL_INT(((int)Segments[i].sides[j].normals[k].x)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].normals[k].y)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].sides[j].normals[k].z)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); } } for (j = 0; j < MAX_SIDES_PER_SEGMENT; j++) { s = INTEL_SHORT(Segments[i].children[j]); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } for (j = 0; j < MAX_VERTICES_PER_SEGMENT; j++) { s = INTEL_SHORT(Segments[i].verts[j]); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } s = INTEL_SHORT(Segments[i].objects); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); do_checksum_calc((unsigned char *)&(Segments[i].special), 1, &sum1, &sum2); do_checksum_calc((unsigned char *)&(Segments[i].matcen_num), 1, &sum1, &sum2); s = INTEL_SHORT(Segments[i].value); do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); t = INTEL_INT(((int)Segments[i].static_light)); do_checksum_calc((ubyte *)&t, 4, &sum1, &sum2); s = INTEL_SHORT(0); // no matter if we need alignment on our platform, if we have editor we MUST consider this integer to get the same checksum as non-editor games calculate do_checksum_calc((ubyte *)&s, 2, &sum1, &sum2); } sum2 %= 255; return ((sum1<<8)+ sum2); } //load a level off disk. level numbers start at 1. Secret levels are -1,-2,-3 void LoadLevel(int level_num,int page_in_textures) { char *level_name; player save_player; save_player = Players[Player_num]; Assert(level_num <= Last_level && level_num >= Last_secret_level && level_num != 0); level_name = get_level_file(level_num); if (!load_level(level_name)) Current_level_num=level_num; gr_use_palette_table( "palette.256" ); show_boxed_message(TXT_LOADING, 0); #ifdef RELEASE timer_delay(F1_0); #endif #ifdef NETWORK my_segments_checksum = netmisc_calc_checksum(); #endif load_endlevel_data(level_num); load_custom_data(level_name); #ifdef NETWORK reset_network_objects(); #endif Players[Player_num] = save_player; set_sound_sources(); songs_play_level_song( Current_level_num, 0 ); gr_palette_load(gr_palette); //actually load the palette if ( page_in_textures ) piggy_load_level_data(); } //sets up Player_num & ConsoleObject void InitPlayerObject() { Assert(Player_num>=0 && Player_numtype = OBJ_PLAYER; ConsoleObject->id = Player_num; ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; } //starts a new game on the given level void StartNewGame(int start_level) { state_quick_item = -1; // for first blind save, pick slot to save in Game_mode = GM_NORMAL; Next_level_num = 0; InitPlayerObject(); //make sure player's object set up init_player_stats_game(Player_num); //clear all stats N_players = 1; StartNewLevel(start_level); Players[Player_num].starting_level = start_level; // Mark where they started game_disable_cheats(); } // ----------------------------------------------------------------------------- // Does the bonus scoring. // Call with dead_flag = 1 if player died, but deserves some portion of bonus (only skill points), anyway. void DoEndLevelScoreGlitz(int network) { int level_points, skill_points, energy_points, shield_points, hostage_points; int all_hostage_points; int endgame_points; char all_hostage_text[64]; char endgame_text[64]; #define N_GLITZITEMS 9 char m_str[N_GLITZITEMS][30]; newmenu_item m[9]; int i,c; char title[128]; int is_last_level; gr_palette_load( gr_palette ); level_points = Players[Player_num].score-Players[Player_num].last_score; if (!cheats.enabled) { if (Difficulty_level > 1) { skill_points = level_points*(Difficulty_level-1)/2; skill_points -= skill_points % 100; } else skill_points = 0; shield_points = f2i(Players[Player_num].shields) * 10 * (Difficulty_level+1); energy_points = f2i(Players[Player_num].energy) * 5 * (Difficulty_level+1); hostage_points = Players[Player_num].hostages_on_board * 500 * (Difficulty_level+1); } else { skill_points = 0; shield_points = 0; energy_points = 0; hostage_points = 0; } all_hostage_text[0] = 0; endgame_text[0] = 0; if (!cheats.enabled && (Players[Player_num].hostages_on_board == Players[Player_num].hostages_level)) { all_hostage_points = Players[Player_num].hostages_on_board * 1000 * (Difficulty_level+1); sprintf(all_hostage_text, "%s%i\n", TXT_FULL_RESCUE_BONUS, all_hostage_points); } else all_hostage_points = 0; if (!cheats.enabled && !(Game_mode & GM_MULTI) && (Players[Player_num].lives) && (Current_level_num == Last_level)) { //player has finished the game! endgame_points = Players[Player_num].lives * 10000; sprintf(endgame_text, "%s%i\n", TXT_SHIP_BONUS, endgame_points); is_last_level=1; } else endgame_points = is_last_level = 0; add_bonus_points_to_score(skill_points + energy_points + shield_points + hostage_points + all_hostage_points + endgame_points); c = 0; sprintf(m_str[c++], "%s%i", TXT_SHIELD_BONUS, shield_points); // Return at start to lower menu... sprintf(m_str[c++], "%s%i", TXT_ENERGY_BONUS, energy_points); sprintf(m_str[c++], "%s%i", TXT_HOSTAGE_BONUS, hostage_points); sprintf(m_str[c++], "%s%i", TXT_SKILL_BONUS, skill_points); sprintf(m_str[c++], "%s", all_hostage_text); if (!(Game_mode & GM_MULTI) && (Players[Player_num].lives) && (Current_level_num == Last_level)) sprintf(m_str[c++], "%s", endgame_text); sprintf(m_str[c++], "%s%i\n", TXT_TOTAL_BONUS, shield_points+energy_points+hostage_points+skill_points+all_hostage_points+endgame_points); sprintf(m_str[c++], "%s%i", TXT_TOTAL_SCORE, Players[Player_num].score); for (i=0; itype) { case EVENT_WINDOW_DRAW: gr_set_current_canvas(NULL); show_fullscr(background); break; default: break; } return 0; } void do_screen_message(char *fmt, ...) { va_list arglist; grs_bitmap background; char msg[1024]; if (Game_mode & GM_MULTI) return; gr_init_bitmap_data(&background); if (pcx_read_bitmap(Menu_pcx_name, &background, BM_LINEAR, gr_palette) != PCX_ERROR_NONE) return; gr_palette_load(gr_palette); va_start(arglist, fmt); vsprintf(msg, fmt, arglist); va_end(arglist); nm_messagebox1(NULL, (int (*)(newmenu *, d_event *, void *))draw_rock, &background, 1, TXT_OK, msg); gr_free_bitmap_data(&background); } //called when the player has finished a level void PlayerFinishedLevel(int secret_flag) { int rval; int was_multi = 0; if (Game_wind) window_set_visible(Game_wind, 0); //credit the player for hostages Players[Player_num].hostages_rescued_total += Players[Player_num].hostages_on_board; #ifndef SHAREWARE if (!(Game_mode & GM_MULTI) && (secret_flag)) { newmenu_item m[1]; m[0].type = NM_TYPE_TEXT; m[0].text = " "; //TXT_SECRET_EXIT; newmenu_do2(NULL, TXT_SECRET_EXIT, 1, m, NULL, NULL, 0, Menu_pcx_name); } #endif // -- mk mk mk -- used to be here -- mk mk mk -- #ifdef NETWORK if (Game_mode & GM_NETWORK) { if (secret_flag) Players[Player_num].connected = CONNECT_FOUND_SECRET; // Finished and went to secret level else Players[Player_num].connected = CONNECT_WAITING; // Finished but did not die } #endif last_drawn_cockpit = -1; if (Current_level_num == Last_level) { #ifdef NETWORK if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { was_multi = 1; multi_endlevel_score(); rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) } else #endif { // Note link to above else! rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) DoEndLevelScoreGlitz(0); //give bonuses } } else { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_endlevel_score(); else #endif // Note link!! DoEndLevelScoreGlitz(0); //give bonuses rval = AdvanceLevel(secret_flag); //now go on to the next one (if one) } if (!was_multi && rval) { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } else if (rval && Game_wind) window_close(Game_wind); if (Game_wind) window_set_visible(Game_wind, 1); reset_time(); } //from which level each do you get to each secret level // int Secret_level_table[MAX_SECRET_LEVELS_PER_MISSION]; //called to go to the next level (if there is one) //if secret_flag is true, advance to secret level, else next normal one // Return true if game over. int AdvanceLevel(int secret_flag) { Control_center_destroyed = 0; #ifdef EDITOR if (Current_level_num == 0) { return 1; //not a real level } #endif key_flush(); #ifdef NETWORK if (Game_mode & GM_MULTI) { int result; result = multi_endlevel(&secret_flag); // Wait for other players to reach this point if (result) // failed to sync { return (Current_level_num == Last_level); } } #endif key_flush(); if (Current_level_num == Last_level) { //player has finished the game! if ((Newdemo_state == ND_STATE_RECORDING) || (Newdemo_state == ND_STATE_PAUSED)) newdemo_stop_recording(); do_end_briefing_screens(Ending_text_filename); return 1; } else { Next_level_num = Current_level_num+1; //assume go to next normal level if (secret_flag) { //go to secret level instead int i; for (i=0;i<-Last_secret_level;i++) if (Secret_level_table[i]==Current_level_num) { Next_level_num = -(i+1); break; } Assert(i<-Last_secret_level); //couldn't find which secret level } if (Current_level_num < 0) { //on secret level, where to go? Assert(!secret_flag); //shouldn't be going to secret level Assert(Current_level_num<=-1 && Current_level_num>=Last_secret_level); Next_level_num = Secret_level_table[(-Current_level_num)-1]+1; } StartNewLevel(Next_level_num); } key_flush(); return 0; } //called when the player has died void DoPlayerDead() { if (Game_wind) window_set_visible(Game_wind, 0); reset_palette_add(); gr_palette_load (gr_palette); dead_player_end(); //terminate death sequence (if playing) #ifdef EDITOR if (Game_mode == GM_EDITOR) { //test mine, not real level object * player = &Objects[Players[Player_num].objnum]; //nm_messagebox( "You're Dead!", 1, "Continue", "Not a real game, though." ); if (Game_wind) window_set_visible(Game_wind, 1); load_level("gamesave.lvl"); init_player_stats_new_ship(Player_num); player->flags &= ~OF_SHOULD_BE_DEAD; StartLevel(0); return; } #endif #ifdef NETWORK if ( Game_mode&GM_MULTI ) { multi_do_death(Players[Player_num].objnum); } else #endif { //Note link to above else! Players[Player_num].lives--; if (Players[Player_num].lives == 0) { DoGameOver(); return; } } if ( Control_center_destroyed ) { int rval; //clear out stuff so no bonus Players[Player_num].hostages_on_board = 0; Players[Player_num].energy = 0; Players[Player_num].shields = 0; #ifdef NETWORK Players[Player_num].connected = CONNECT_DIED_IN_MINE; #endif do_screen_message(TXT_DIED_IN_MINE); // Give them some indication of what happened if (Current_level_num == Last_level) { #ifdef NETWORK if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { multi_endlevel_score(); rval = AdvanceLevel(0); //if finished, go on to next level } else #endif { // Note link to above else! rval = AdvanceLevel(0); //if finished, go on to next level DoEndLevelScoreGlitz(0); } init_player_stats_new_ship(Player_num); last_drawn_cockpit = -1; } else { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_endlevel_score(); else #endif DoEndLevelScoreGlitz(0); // Note above link! rval = AdvanceLevel(0); //if finished, go on to next level init_player_stats_new_ship(Player_num); last_drawn_cockpit = -1; } if (rval) { #ifndef SHAREWARE if (PLAYING_BUILTIN_MISSION) #endif scores_maybe_add_player(0); if (Game_wind) window_close(Game_wind); // Exit out of game loop } } else { init_player_stats_new_ship(Player_num); StartLevel(1); } if (Game_wind) window_set_visible(Game_wind, 1); reset_time(); } //called when the player is starting a new level for normal game mode and restore state void StartNewLevelSub(int level_num, int page_in_textures, int secret_flag) { /* * This flag is present for compatibility with D2X. Set it to zero * so the optimizer deletes all reference to it. */ secret_flag = 0; if (!(Game_mode & GM_MULTI)) { last_drawn_cockpit = -1; } if (Newdemo_state == ND_STATE_PAUSED) Newdemo_state = ND_STATE_RECORDING; if (Newdemo_state == ND_STATE_RECORDING) { newdemo_set_new_level(level_num); newdemo_record_start_frame(FrameTime ); } LoadLevel(level_num, page_in_textures); Assert(Current_level_num == level_num); //make sure level set right gameseq_init_network_players(); // Initialize the Players array for // this level #ifdef NETWORK if (Game_mode & GM_NETWORK) { if(multi_level_sync()) // After calling this, Player_num is set { songs_play_song( SONG_TITLE, 1 ); // level song already plays but we fail to start level... return; } } #endif HUD_clear_messages(); automap_clear_visited(); init_player_stats_level(secret_flag); gr_use_palette_table( "palette.256" ); gr_palette_load(gr_palette); #ifndef SHAREWARE #ifdef NETWORK if ((Game_mode & GM_MULTI_COOP) && Network_rejoined) { int i; for (i = 0; i < N_players; i++) Players[i].flags |= Netgame.player_flags[i]; } #endif #endif Viewer = &Objects[Players[Player_num].objnum]; #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_prep_level(); // Removes robots from level if necessary } #endif gameseq_remove_unused_players(); Game_suspended = 0; Control_center_destroyed = 0; init_cockpit(); init_robots_for_level(); init_ai_objects(); init_morphs(); init_all_matcens(); reset_palette_add(); if (!(Game_mode & GM_MULTI) && !cheats.enabled) set_highest_level(Current_level_num); reset_special_effects(); #ifdef OGL ogl_cache_level_textures(); #endif #ifdef NETWORK if (Network_rejoined == 1) { Network_rejoined = 0; StartLevel(1); } else #endif StartLevel(0); // Note link to above if! copy_defaults_to_robot_all(); init_controlcen_for_level(); // Say player can use FLASH cheat to mark path to exit. Last_level_path_created = -1; // Initialise for palette_restore() if (!((Game_mode & GM_MULTI) && (Newdemo_state != ND_STATE_PLAYBACK))) palette_save(); if (!Game_wind) game(); } #ifdef NETWORK extern char PowerupsInMine[MAX_POWERUP_TYPES], MaxPowerupsAllowed[MAX_POWERUP_TYPES]; #endif void bash_to_shield (int i,char *s) { #ifdef NETWORK int type=Objects[i].id; #endif #ifdef NETWORK PowerupsInMine[type]=MaxPowerupsAllowed[type]=0; #endif Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } //called when the player is starting a new level for normal game model void StartNewLevel(int level_num) { hide_menus(); GameTime64 = 0; ThisLevelTime=0; if (!(Game_mode & GM_MULTI)) { do_briefing_screens(Briefing_text_filename, level_num); } StartNewLevelSub(level_num, 1, 0 ); } //initialize the player object position & orientation (at start of game, or new ship) void InitPlayerPosition(int random) { int NewPlayer=0; if (! ((Game_mode & GM_MULTI) && !(Game_mode&GM_MULTI_COOP)) ) // If not deathmatch NewPlayer = Player_num; else if (random == 1) { int i, trys=0; fix closest_dist = 0x7ffffff, dist; timer_update(); d_srand((fix)timer_query()); do { trys++; NewPlayer = d_rand() % NumNetPlayerPositions; closest_dist = 0x7fffffff; for (i=0; i= 0) ) { closest_dist = dist; } } } } while ( (closest_dist= 0); Assert(NewPlayer < NumNetPlayerPositions); ConsoleObject->pos = Player_init[NewPlayer].pos; ConsoleObject->orient = Player_init[NewPlayer].orient; obj_relink(ConsoleObject-Objects,Player_init[NewPlayer].segnum); reset_player_object(); reset_cruise(); } // ----------------------------------------------------------------------------------------------------- // Initialize default parameters for one robot, copying from Robot_info to *objp. // What about setting size!? Where does that come from? void copy_defaults_to_robot(object *objp) { robot_info *robptr; int objid; Assert(objp->type == OBJ_ROBOT); objid = objp->id; Assert(objid < N_robot_types); robptr = &Robot_info[objid]; objp->shields = robptr->strength; } // ----------------------------------------------------------------------------------------------------- // Copy all values from the robot info structure to all instances of robots. // This allows us to change bitmaps.tbl and have these changes manifested in existing robots. // This function should be called at level load time. void copy_defaults_to_robot_all(void) { int i; for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_ROBOT) copy_defaults_to_robot(&Objects[i]); } int Do_appearance_effect=0; // ----------------------------------------------------------------------------------------------------- //called when the player is starting a level (new game or new ship) void StartLevel(int random) { Assert(!Player_is_dead); InitPlayerPosition(random); verify_console_object(); ConsoleObject->control_type = CT_FLYING; ConsoleObject->movement_type = MT_PHYSICS; // create_player_appearance_effect(ConsoleObject); Do_appearance_effect = 1; if (Game_mode & GM_MULTI) { if (Game_mode & GM_MULTI_COOP) multi_send_score(); multi_send_reappear(); multi_do_protocol_frame(1, 1); } else // in Singleplayer, after we died ... { disable_matcens(); // ... disable matcens and ... clear_transient_objects(0); // ... clear all transient objects. } ai_reset_all_paths(); ai_init_boss_for_ship(); reset_rear_view(); Auto_fire_fusion_cannon_time = 0; Fusion_charge = 0; if (!(Game_mode & GM_MULTI)) // stuff for Singleplayer only { } } dxx-rebirth-0.58.1-d1x/main/gameseq.h000066400000000000000000000066011217717257200172740ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes for functions for game sequencing. * */ #ifndef _GAMESEQ_H #define _GAMESEQ_H #include "player.h" #include "mission.h" #include "object.h" #define SUPER_MISSILE 0 #define SUPER_SEEKER 1 #define SUPER_SMARTBOMB 2 #define SUPER_SHOCKWAVE 3 #ifdef SHAREWARE #define Last_level 7 //the number of the very last level for shareware #define Last_secret_level 0 // No secret levels! // #else // extern int Last_level,Last_secret_level; //set by mission code #endif // extern int Secret_level_table[MAX_SECRET_LEVELS_PER_MISSION]; #define LEVEL_NAME_LEN 36 //make sure this is multiple of 4! // Current_level_num starts at 1 for the first level // -1,-2,-3 are secret levels // 0 means not a real level loaded extern int Current_level_num, Next_level_num; extern char Current_level_name[LEVEL_NAME_LEN]; extern obj_position Player_init[MAX_PLAYERS]; // This is the highest level the player has ever reached extern int Player_highest_level; // // New game sequencing functions // // starts a new game on the given level void StartNewGame(int start_level); // starts the next level void StartNewLevel(int level_num); // Actually does the work to start new level void StartNewLevelSub(int level_num, int page_in_textures, int secret_flag); void InitPlayerObject(); //make sure player's object set up void init_player_stats_game(ubyte pnum); //clear all stats // called when the player has finished a level // if secret flag is true, advance to secret level, else next normal level void PlayerFinishedLevel(int secret_flag); // called when the player has died void DoPlayerDead(void); // load a level off disk. level numbers start at 1. // Secret levels are -1,-2,-3 void LoadLevel(int level_num,int page_in_textures); extern void gameseq_remove_unused_players(); extern void update_player_stats(); // from scores.c extern void show_high_scores(int place); extern void draw_high_scores(int place); extern int add_player_to_high_scores(player *pp); extern void input_name (int place); extern int reset_high_scores(); extern void init_player_stats_level(int secret_flag); void open_message_window(void); void close_message_window(void); // create flash for player appearance extern void create_player_appearance_effect(object *player_obj); // goto whatever secrect level is appropriate given the current level //extern int goto_secret_level(); // reset stuff so game is semi-normal when playing from editor void editor_reset_stuff_on_level(); // Show endlevel bonus scores extern void DoEndLevelScoreGlitz(int network); // stuff for multiplayer extern int NumNetPlayerPositions; void bash_to_shield(int, char *); #endif /* _GAMESEQ_H */ dxx-rebirth-0.58.1-d1x/main/gauges.c000066400000000000000000002261131217717257200171220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Inferno gauge drivers * */ #include #include #include #include #include "inferno.h" #include "game.h" #include "screens.h" #include "gauges.h" #include "physics.h" #include "dxxerror.h" #include "menu.h" #include "collide.h" #include "newdemo.h" #include "player.h" #include "gamefont.h" #include "hostage.h" #include "bm.h" #include "text.h" #include "powerup.h" #include "sounds.h" #include "multi.h" #include "endlevel.h" #include "wall.h" #include "text.h" #include "render.h" #include "piggy.h" #include "laser.h" #include "playsave.h" #include "rle.h" #include "byteswap.h" #include "cntrlcen.h" #ifdef OGL #include "ogl_init.h" #endif //bitmap numbers for gauges #define GAUGE_SHIELDS 0 //0..9, in decreasing order (100%,90%...0%) #define GAUGE_INVULNERABLE 10 //10..19 #define N_INVULNERABLE_FRAMES 10 #define GAUGE_SPEED 20 //unused #define GAUGE_ENERGY_LEFT 21 #define GAUGE_ENERGY_RIGHT 22 #define GAUGE_NUMERICAL 23 #define GAUGE_BLUE_KEY 24 #define GAUGE_GOLD_KEY 25 #define GAUGE_RED_KEY 26 #define GAUGE_BLUE_KEY_OFF 27 #define GAUGE_GOLD_KEY_OFF 28 #define GAUGE_RED_KEY_OFF 29 #define SB_GAUGE_BLUE_KEY 30 #define SB_GAUGE_GOLD_KEY 31 #define SB_GAUGE_RED_KEY 32 #define SB_GAUGE_BLUE_KEY_OFF 33 #define SB_GAUGE_GOLD_KEY_OFF 34 #define SB_GAUGE_RED_KEY_OFF 35 #define SB_GAUGE_ENERGY 36 #define GAUGE_LIVES 37 #define GAUGE_SHIPS 38 #define GAUGE_SHIPS_LAST 45 #define RETICLE_CROSS 46 #define RETICLE_PRIMARY 48 #define RETICLE_SECONDARY 51 #define RETICLE_LAST 55 #define GAUGE_HOMING_WARNING_ON 56 #define GAUGE_HOMING_WARNING_OFF 57 #define SML_RETICLE_CROSS 58 #define SML_RETICLE_PRIMARY 60 #define SML_RETICLE_SECONDARY 63 #define SML_RETICLE_LAST 67 #define KEY_ICON_BLUE 68 #define KEY_ICON_YELLOW 69 #define KEY_ICON_RED 70 //Coordinats for gauges // cockpit keys #define GAUGE_BLUE_KEY_X_L 45 #define GAUGE_BLUE_KEY_Y_L 152 #define GAUGE_BLUE_KEY_X_H 91 #define GAUGE_BLUE_KEY_Y_H 374 #define GAUGE_BLUE_KEY_X (HIRESMODE?GAUGE_BLUE_KEY_X_H:GAUGE_BLUE_KEY_X_L) #define GAUGE_BLUE_KEY_Y (HIRESMODE?GAUGE_BLUE_KEY_Y_H:GAUGE_BLUE_KEY_Y_L) #define GAUGE_GOLD_KEY_X_L 44 #define GAUGE_GOLD_KEY_Y_L 162 #define GAUGE_GOLD_KEY_X_H 89 #define GAUGE_GOLD_KEY_Y_H 395 #define GAUGE_GOLD_KEY_X (HIRESMODE?GAUGE_GOLD_KEY_X_H:GAUGE_GOLD_KEY_X_L) #define GAUGE_GOLD_KEY_Y (HIRESMODE?GAUGE_GOLD_KEY_Y_H:GAUGE_GOLD_KEY_Y_L) #define GAUGE_RED_KEY_X_L 43 #define GAUGE_RED_KEY_Y_L 172 #define GAUGE_RED_KEY_X_H 87 #define GAUGE_RED_KEY_Y_H 417 #define GAUGE_RED_KEY_X (HIRESMODE?GAUGE_RED_KEY_X_H:GAUGE_RED_KEY_X_L) #define GAUGE_RED_KEY_Y (HIRESMODE?GAUGE_RED_KEY_Y_H:GAUGE_RED_KEY_Y_L) // status bar keys #define SB_GAUGE_KEYS_X_L 11 #define SB_GAUGE_KEYS_X_H 26 #define SB_GAUGE_KEYS_X (HIRESMODE?SB_GAUGE_KEYS_X_H:SB_GAUGE_KEYS_X_L) #define SB_GAUGE_BLUE_KEY_Y_L 153 #define SB_GAUGE_GOLD_KEY_Y_L 169 #define SB_GAUGE_RED_KEY_Y_L 185 #define SB_GAUGE_BLUE_KEY_Y_H 390 #define SB_GAUGE_GOLD_KEY_Y_H 422 #define SB_GAUGE_RED_KEY_Y_H 454 #define SB_GAUGE_BLUE_KEY_Y (HIRESMODE?SB_GAUGE_BLUE_KEY_Y_H:SB_GAUGE_BLUE_KEY_Y_L) #define SB_GAUGE_GOLD_KEY_Y (HIRESMODE?SB_GAUGE_GOLD_KEY_Y_H:SB_GAUGE_GOLD_KEY_Y_L) #define SB_GAUGE_RED_KEY_Y (HIRESMODE?SB_GAUGE_RED_KEY_Y_H:SB_GAUGE_RED_KEY_Y_L) // cockpit enery gauges #define LEFT_ENERGY_GAUGE_X_L 70 #define LEFT_ENERGY_GAUGE_Y_L 131 #define LEFT_ENERGY_GAUGE_W_L 64 #define LEFT_ENERGY_GAUGE_H_L 8 #define LEFT_ENERGY_GAUGE_X_H 137 #define LEFT_ENERGY_GAUGE_Y_H 314 #define LEFT_ENERGY_GAUGE_W_H 133 #define LEFT_ENERGY_GAUGE_H_H 21 #define LEFT_ENERGY_GAUGE_X (HIRESMODE?LEFT_ENERGY_GAUGE_X_H:LEFT_ENERGY_GAUGE_X_L) #define LEFT_ENERGY_GAUGE_Y (HIRESMODE?LEFT_ENERGY_GAUGE_Y_H:LEFT_ENERGY_GAUGE_Y_L) #define LEFT_ENERGY_GAUGE_W (HIRESMODE?LEFT_ENERGY_GAUGE_W_H:LEFT_ENERGY_GAUGE_W_L) #define LEFT_ENERGY_GAUGE_H (HIRESMODE?LEFT_ENERGY_GAUGE_H_H:LEFT_ENERGY_GAUGE_H_L) #define RIGHT_ENERGY_GAUGE_X (HIRESMODE?380:190) #define RIGHT_ENERGY_GAUGE_Y (HIRESMODE?314:131) #define RIGHT_ENERGY_GAUGE_W (HIRESMODE?133:64) #define RIGHT_ENERGY_GAUGE_H (HIRESMODE?21:8) // sb energy gauge #define SB_ENERGY_GAUGE_X (HIRESMODE?196:98) #define SB_ENERGY_GAUGE_Y (HIRESMODE?390:155) #define SB_ENERGY_GAUGE_W (HIRESMODE?32:16) #define SB_ENERGY_GAUGE_H (HIRESMODE?82:41) #define SB_ENERGY_NUM_X (SB_ENERGY_GAUGE_X+(HIRESMODE?4:2)) #define SB_ENERGY_NUM_Y (HIRESMODE?457:190) #define SHIELD_GAUGE_X (HIRESMODE?292:146) #define SHIELD_GAUGE_Y (HIRESMODE?374:155) #define SHIELD_GAUGE_W (HIRESMODE?70:35) #define SHIELD_GAUGE_H (HIRESMODE?77:32) #define SHIP_GAUGE_X (SHIELD_GAUGE_X+(HIRESMODE?11:5)) #define SHIP_GAUGE_Y (SHIELD_GAUGE_Y+(HIRESMODE?10:5)) #define SB_SHIELD_GAUGE_X (HIRESMODE?247:123) //139 #define SB_SHIELD_GAUGE_Y (HIRESMODE?395:163) #define SB_SHIP_GAUGE_X (SB_SHIELD_GAUGE_X+(HIRESMODE?11:5)) #define SB_SHIP_GAUGE_Y (SB_SHIELD_GAUGE_Y+(HIRESMODE?10:5)) #define SB_SHIELD_NUM_X (SB_SHIELD_GAUGE_X+(HIRESMODE?21:12)) //151 #define SB_SHIELD_NUM_Y (SB_SHIELD_GAUGE_Y-(HIRESMODE?16:7)) //156 -- MWA used to be hard coded to 156 #define NUMERICAL_GAUGE_X (HIRESMODE?308:154) #define NUMERICAL_GAUGE_Y (HIRESMODE?316:130) #define NUMERICAL_GAUGE_W (HIRESMODE?38:19) #define NUMERICAL_GAUGE_H (HIRESMODE?55:22) #define PRIMARY_W_PIC_X (HIRESMODE?135:64) #define PRIMARY_W_PIC_Y (HIRESMODE?370:154) #define PRIMARY_W_TEXT_X HUD_SCALE_X(HIRESMODE?182:87) #define PRIMARY_W_TEXT_Y HUD_SCALE_Y(HIRESMODE?400:157) #define PRIMARY_AMMO_X HUD_SCALE_X(HIRESMODE?186:93) #define PRIMARY_AMMO_Y HUD_SCALE_Y(HIRESMODE?420:171) #define SECONDARY_W_PIC_X (HIRESMODE?405:234) #define SECONDARY_W_PIC_Y (HIRESMODE?370:154) #define SECONDARY_W_TEXT_X HUD_SCALE_X(HIRESMODE?462:207) #define SECONDARY_W_TEXT_Y HUD_SCALE_Y(HIRESMODE?400:157) #define SECONDARY_AMMO_X HUD_SCALE_X(HIRESMODE?475:213) #define SECONDARY_AMMO_Y HUD_SCALE_Y(HIRESMODE?425:171) #define SB_LIVES_X (HIRESMODE?550:266) #define SB_LIVES_Y (HIRESMODE?450:185) #define SB_LIVES_LABEL_X (HIRESMODE?475:237) #define SB_LIVES_LABEL_Y (SB_LIVES_Y+1) #define SB_SCORE_RIGHT_L 301 #define SB_SCORE_RIGHT_H 605 #define SB_SCORE_RIGHT (HIRESMODE?SB_SCORE_RIGHT_H:SB_SCORE_RIGHT_L) #define SB_SCORE_Y (HIRESMODE?398:158) #define SB_SCORE_LABEL_X (HIRESMODE?475:237) #define SB_SCORE_ADDED_RIGHT (HIRESMODE?SB_SCORE_RIGHT_H:SB_SCORE_RIGHT_L) #define SB_SCORE_ADDED_Y (HIRESMODE?413:165) #define HOMING_WARNING_X HUD_SCALE_X(HIRESMODE?13:7) #define HOMING_WARNING_Y HUD_SCALE_Y(HIRESMODE?416:171) #define BOMB_COUNT_X (HIRESMODE?468:210) #define BOMB_COUNT_Y (HIRESMODE?445:186) #define SB_BOMB_COUNT_X (HIRESMODE?342:171) #define SB_BOMB_COUNT_Y (HIRESMODE?458:191) // defining box boundries for weapon pictures #define PRIMARY_W_BOX_LEFT_L 63 #define PRIMARY_W_BOX_TOP_L 151 //154 #define PRIMARY_W_BOX_RIGHT_L (PRIMARY_W_BOX_LEFT_L+58) #define PRIMARY_W_BOX_BOT_L (PRIMARY_W_BOX_TOP_L+42) #define PRIMARY_W_BOX_LEFT_H 121 #define PRIMARY_W_BOX_TOP_H 364 #define PRIMARY_W_BOX_RIGHT_H 241 #define PRIMARY_W_BOX_BOT_H (PRIMARY_W_BOX_TOP_H+106) //470 #define PRIMARY_W_BOX_LEFT (HIRESMODE?PRIMARY_W_BOX_LEFT_H:PRIMARY_W_BOX_LEFT_L) #define PRIMARY_W_BOX_TOP (HIRESMODE?PRIMARY_W_BOX_TOP_H:PRIMARY_W_BOX_TOP_L) #define PRIMARY_W_BOX_RIGHT (HIRESMODE?PRIMARY_W_BOX_RIGHT_H:PRIMARY_W_BOX_RIGHT_L) #define PRIMARY_W_BOX_BOT (HIRESMODE?PRIMARY_W_BOX_BOT_H:PRIMARY_W_BOX_BOT_L) #define SECONDARY_W_BOX_LEFT_L 202 //207 #define SECONDARY_W_BOX_TOP_L 151 #define SECONDARY_W_BOX_RIGHT_L 264 //(SECONDARY_W_BOX_LEFT+54) #define SECONDARY_W_BOX_BOT_L (SECONDARY_W_BOX_TOP_L+42) #define SECONDARY_W_BOX_LEFT_H 403 #define SECONDARY_W_BOX_TOP_H 364 #define SECONDARY_W_BOX_RIGHT_H 531 #define SECONDARY_W_BOX_BOT_H (SECONDARY_W_BOX_TOP_H+106) //470 #define SECONDARY_W_BOX_LEFT (HIRESMODE?SECONDARY_W_BOX_LEFT_H:SECONDARY_W_BOX_LEFT_L) #define SECONDARY_W_BOX_TOP (HIRESMODE?SECONDARY_W_BOX_TOP_H:SECONDARY_W_BOX_TOP_L) #define SECONDARY_W_BOX_RIGHT (HIRESMODE?SECONDARY_W_BOX_RIGHT_H:SECONDARY_W_BOX_RIGHT_L) #define SECONDARY_W_BOX_BOT (HIRESMODE?SECONDARY_W_BOX_BOT_H:SECONDARY_W_BOX_BOT_L) #define SB_PRIMARY_W_BOX_LEFT_L 34 //50 #define SB_PRIMARY_W_BOX_TOP_L 154 #define SB_PRIMARY_W_BOX_RIGHT_L (SB_PRIMARY_W_BOX_LEFT_L+55) #define SB_PRIMARY_W_BOX_BOT_L (195) #define SB_PRIMARY_W_BOX_LEFT_H 68 #define SB_PRIMARY_W_BOX_TOP_H 381 #define SB_PRIMARY_W_BOX_RIGHT_H 179 #define SB_PRIMARY_W_BOX_BOT_H 473 #define SB_PRIMARY_W_BOX_LEFT (HIRESMODE?SB_PRIMARY_W_BOX_LEFT_H:SB_PRIMARY_W_BOX_LEFT_L) #define SB_PRIMARY_W_BOX_TOP (HIRESMODE?SB_PRIMARY_W_BOX_TOP_H:SB_PRIMARY_W_BOX_TOP_L) #define SB_PRIMARY_W_BOX_RIGHT (HIRESMODE?SB_PRIMARY_W_BOX_RIGHT_H:SB_PRIMARY_W_BOX_RIGHT_L) #define SB_PRIMARY_W_BOX_BOT (HIRESMODE?SB_PRIMARY_W_BOX_BOT_H:SB_PRIMARY_W_BOX_BOT_L) #define SB_SECONDARY_W_BOX_LEFT_L 169 #define SB_SECONDARY_W_BOX_TOP_L 154 #define SB_SECONDARY_W_BOX_RIGHT_L (SB_SECONDARY_W_BOX_LEFT_L+54) #define SB_SECONDARY_W_BOX_BOT_L (153+42) #define SB_SECONDARY_W_BOX_LEFT_H 338 #define SB_SECONDARY_W_BOX_TOP_H 381 #define SB_SECONDARY_W_BOX_RIGHT_H 449 #define SB_SECONDARY_W_BOX_BOT_H 473 #define SB_SECONDARY_W_BOX_LEFT (HIRESMODE?SB_SECONDARY_W_BOX_LEFT_H:SB_SECONDARY_W_BOX_LEFT_L) //210 #define SB_SECONDARY_W_BOX_TOP (HIRESMODE?SB_SECONDARY_W_BOX_TOP_H:SB_SECONDARY_W_BOX_TOP_L) #define SB_SECONDARY_W_BOX_RIGHT (HIRESMODE?SB_SECONDARY_W_BOX_RIGHT_H:SB_SECONDARY_W_BOX_RIGHT_L) #define SB_SECONDARY_W_BOX_BOT (HIRESMODE?SB_SECONDARY_W_BOX_BOT_H:SB_SECONDARY_W_BOX_BOT_L) #define SB_PRIMARY_W_PIC_X (SB_PRIMARY_W_BOX_LEFT+1) //51 #define SB_PRIMARY_W_PIC_Y (HIRESMODE?382:154) #define SB_PRIMARY_W_TEXT_X HUD_SCALE_X(SB_PRIMARY_W_BOX_LEFT+(HIRESMODE?50:24)) //(51+23) #define SB_PRIMARY_W_TEXT_Y HUD_SCALE_Y(HIRESMODE?390:157) #define SB_PRIMARY_AMMO_X HUD_SCALE_X(SB_PRIMARY_W_BOX_LEFT+(HIRESMODE?58:30)) //((SB_PRIMARY_W_BOX_LEFT+33)-3) //(51+32) #define SB_PRIMARY_AMMO_Y HUD_SCALE_Y(HIRESMODE?410:171) #define SB_SECONDARY_W_PIC_X (HIRESMODE?385:(SB_SECONDARY_W_BOX_LEFT+27)) //(212+27) #define SB_SECONDARY_W_PIC_Y (HIRESMODE?382:154) #define SB_SECONDARY_W_TEXT_X HUD_SCALE_X(SB_SECONDARY_W_BOX_LEFT+2) //212 #define SB_SECONDARY_W_TEXT_Y HUD_SCALE_Y(HIRESMODE?390:157) #define SB_SECONDARY_AMMO_X HUD_SCALE_X(SB_SECONDARY_W_BOX_LEFT+(HIRESMODE?(14):11)) //(212+9) #define SB_SECONDARY_AMMO_Y HUD_SCALE_Y(HIRESMODE?414:171) #define WS_SET 0 //in correct state #define WS_FADING_OUT 1 #define WS_FADING_IN 2 #define FADE_SCALE (2*i2f(GR_FADE_LEVELS)/REARM_TIME) // fade out and back in REARM_TIME, in fade levels per seconds (int) #define MAX_SHOWN_LIVES 4 #define COCKPIT_PRIMARY_BOX (!HIRESMODE?0:4) #define COCKPIT_SECONDARY_BOX (!HIRESMODE?1:5) #define SB_PRIMARY_BOX (!HIRESMODE?2:6) #define SB_SECONDARY_BOX (!HIRESMODE?3:7) // scaling gauges #define BASE_WIDTH (HIRESMODE? 640 : 320) #define BASE_HEIGHT (HIRESMODE? 480 : 200) #ifdef OGL #define HUD_SCALE_X(x) ((int) ((double) (x) * ((double)grd_curscreen->sc_w/BASE_WIDTH) + 0.5)) #define HUD_SCALE_Y(y) ((int) ((double) (y) * ((double)grd_curscreen->sc_h/BASE_HEIGHT) + 0.5)) #define HUD_SCALE_X_AR(x) (HUD_SCALE_X(100) > HUD_SCALE_Y(100) ? HUD_SCALE_Y(x) : HUD_SCALE_X(x)) #define HUD_SCALE_Y_AR(y) (HUD_SCALE_Y(100) > HUD_SCALE_X(100) ? HUD_SCALE_X(y) : HUD_SCALE_Y(y)) #else #define HUD_SCALE_X(x) (x) #define HUD_SCALE_Y(y) (y) #define HUD_SCALE_X_AR(x) (x) #define HUD_SCALE_Y_AR(y) (y) #endif bitmap_index Gauges[MAX_GAUGE_BMS_MAC]; // Array of all gauge bitmaps. grs_bitmap deccpt; grs_bitmap *WinBoxOverlay[2] = { NULL, NULL }; // Overlay subbitmaps for both weapon boxes static int score_display; static fix score_time; static int old_weapon[2] = {-1,-1}; static int invulnerable_frame = 0; int weapon_box_states[2]; fix weapon_box_fade_values[2]; int Color_0_31_0 = -1; extern fix ThisLevelTime; extern fix Cruise_speed; typedef struct gauge_box { int left,top; int right,bot; //maximal box } gauge_box; //first two are primary & secondary //seconds two are the same for the status bar gauge_box gauge_boxes[] = { // primary left/right low res {PRIMARY_W_BOX_LEFT_L,PRIMARY_W_BOX_TOP_L,PRIMARY_W_BOX_RIGHT_L,PRIMARY_W_BOX_BOT_L}, {SECONDARY_W_BOX_LEFT_L,SECONDARY_W_BOX_TOP_L,SECONDARY_W_BOX_RIGHT_L,SECONDARY_W_BOX_BOT_L}, //sb left/right low res {SB_PRIMARY_W_BOX_LEFT_L,SB_PRIMARY_W_BOX_TOP_L,SB_PRIMARY_W_BOX_RIGHT_L,SB_PRIMARY_W_BOX_BOT_L}, {SB_SECONDARY_W_BOX_LEFT_L,SB_SECONDARY_W_BOX_TOP_L,SB_SECONDARY_W_BOX_RIGHT_L,SB_SECONDARY_W_BOX_BOT_L}, // primary left/right hires {PRIMARY_W_BOX_LEFT_H,PRIMARY_W_BOX_TOP_H,PRIMARY_W_BOX_RIGHT_H,PRIMARY_W_BOX_BOT_H}, {SECONDARY_W_BOX_LEFT_H,SECONDARY_W_BOX_TOP_H,SECONDARY_W_BOX_RIGHT_H,SECONDARY_W_BOX_BOT_H}, // sb left/right hires {SB_PRIMARY_W_BOX_LEFT_H,SB_PRIMARY_W_BOX_TOP_H,SB_PRIMARY_W_BOX_RIGHT_H,SB_PRIMARY_W_BOX_BOT_H}, {SB_SECONDARY_W_BOX_LEFT_H,SB_SECONDARY_W_BOX_TOP_H,SB_SECONDARY_W_BOX_RIGHT_H,SB_SECONDARY_W_BOX_BOT_H}, }; //store delta x values from left of box span weapon_window_left[] = { {71,114}, {69,116}, {68,117}, {66,118}, {66,119}, {66,119}, {65,119}, {65,119}, {65,119}, {65,119}, {65,119}, {65,119}, {65,119}, {65,119}, {65,119}, {64,119}, {64,119}, {64,119}, {64,119}, {64,119}, {64,119}, {64,119}, {64,119}, {64,119}, {63,119}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,118}, {63,117}, {63,117}, {64,116}, {65,115}, {66,113}, {68,111}, }; //store delta x values from left of box span weapon_window_right[] = { {208,255}, {206,257}, {205,258}, {204,259}, {203,260}, {203,260}, {203,260}, {203,260}, {203,260}, {203,261}, {203,261}, {203,261}, {203,261}, {203,261}, {203,261}, {203,261}, {203,261}, {203,261}, {203,262}, {203,262}, {203,262}, {203,262}, {203,262}, {203,262}, {203,262}, {203,262}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {204,263}, {205,263}, {206,262}, {207,261}, {208,260}, {211,255}, }; //store delta x values from left of box span weapon_window_left_hires[] = { {141,231}, {139,234}, {137,235}, {136,237}, {135,238}, {134,239}, {133,240}, {132,240}, {131,241}, {131,241}, {130,242}, {129,242}, {129,242}, {129,243}, {128,243}, {128,243}, {128,243}, {128,243}, {128,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {127,243}, {126,243}, {126,243}, {126,243}, {126,243}, {126,242}, {126,242}, {126,242}, {126,242}, {126,242}, {126,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {125,242}, {124,242}, {124,242}, {124,241}, {124,241}, {124,241}, {124,241}, {124,241}, {124,241}, {124,241}, {124,241}, {124,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {123,241}, {122,241}, {122,241}, {122,240}, {122,240}, {122,240}, {122,240}, {122,240}, {122,240}, {122,240}, {122,240}, {121,240}, {121,240}, {121,240}, {121,240}, {121,240}, {121,240}, {121,240}, {121,239}, {121,239}, {121,239}, {121,238}, {121,238}, {121,238}, {122,237}, {122,237}, {123,236}, {123,235}, {124,234}, {125,233}, {126,232}, {126,231}, {128,230}, {130,228}, {131,226}, {133,223}, }; //store delta x values from left of box span weapon_window_right_hires[] = { {416,509}, {413,511}, {412,513}, {410,514}, {409,515}, {408,516}, {407,517}, {407,518}, {406,519}, {406,519}, {405,520}, {405,521}, {405,521}, {404,521}, {404,522}, {404,522}, {404,522}, {404,522}, {404,522}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,523}, {404,524}, {404,524}, {404,524}, {404,524}, {405,524}, {405,524}, {405,524}, {405,524}, {405,524}, {405,524}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,525}, {405,526}, {405,526}, {406,526}, {406,526}, {406,526}, {406,526}, {406,526}, {406,526}, {406,526}, {406,526}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,527}, {406,528}, {406,528}, {407,528}, {407,528}, {407,528}, {407,528}, {407,528}, {407,528}, {407,528}, {407,529}, {407,529}, {407,529}, {407,529}, {407,529}, {407,529}, {407,529}, {407,529}, {408,529}, {408,529}, {408,529}, {409,529}, {409,529}, {409,529}, {410,529}, {410,528}, {411,527}, {412,527}, {413,526}, {414,525}, {415,524}, {416,524}, {417,522}, {419,521}, {422,519}, {424,518}, }; static inline void hud_bitblt_free (int x, int y, int w, int h, grs_bitmap *bm) { #ifdef OGL ogl_ubitmapm_cs (x,y,w,h,bm,-1,F1_0); #else gr_ubitmapm(x, y, bm); #endif } static inline void hud_bitblt (int x, int y, grs_bitmap *bm) { #ifdef OGL ogl_ubitmapm_cs (x,y,HUD_SCALE_X (bm->bm_w),HUD_SCALE_Y (bm->bm_h),bm,-1,F1_0); #else gr_ubitmapm(x, y, bm); #endif } void hud_show_score() { char score_str[20]; int w, h, aw; if (HUD_toolong) return; gr_set_curfont( GAME_FONT ); if ( ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) ) { sprintf(score_str, "%s: %5d", TXT_KILLS, Players[Player_num].net_kills_total); } else { sprintf(score_str, "%s: %5d", TXT_SCORE, Players[Player_num].score); } gr_get_string_size(score_str, &w, &h, &aw ); if (Color_0_31_0 == -1) Color_0_31_0 = BM_XRGB(0,31,0); gr_set_fontcolor(Color_0_31_0, -1); gr_string(grd_curcanv->cv_bitmap.bm_w-w-FSPACX(1), FSPACY(1), score_str); } void hud_show_timer_count() { #ifdef NETWORK char score_str[20]; int w, h, aw,i; fix timevar=0; #endif if (HUD_toolong) return; #ifdef NETWORK if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed) { timevar=i2f (Netgame.PlayTimeAllowed*5*60); i=f2i(timevar-ThisLevelTime); i++; sprintf(score_str, "T - %5d", i); gr_get_string_size(score_str, &w, &h, &aw ); if (Color_0_31_0 == -1) Color_0_31_0 = BM_XRGB(0,31,0); gr_set_fontcolor(Color_0_31_0, -1); if (i>-1 && !Control_center_destroyed) gr_string(grd_curcanv->cv_bitmap.bm_w-w-FSPACX(12), LINE_SPACING+FSPACY(1), score_str); } #endif } void hud_show_score_added() { int color; int w, h, aw; char score_str[20]; if ( (Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) ) return; if (score_display == 0) return; gr_set_curfont( GAME_FONT ); score_time -= FrameTime; if (score_time > 0) { color = f2i(score_time * 20) + 12; if (color < 10) color = 12; if (color > 31) color = 30; color = color - (color % 4); if (cheats.enabled) sprintf(score_str, "%s", TXT_CHEATER); else sprintf(score_str, "%5d", score_display); gr_get_string_size(score_str, &w, &h, &aw ); gr_set_fontcolor(BM_XRGB(0, color, 0),-1 ); gr_string(grd_curcanv->cv_bitmap.bm_w-w-FSPACX(12), LINE_SPACING+FSPACY(1), score_str); } else { score_time = 0; score_display = 0; } } void sb_show_score() { char score_str[20]; int x,y; int w, h, aw; gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); if ( (Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) ) gr_printf(HUD_SCALE_X(SB_SCORE_LABEL_X),HUD_SCALE_Y(SB_SCORE_Y),"%s:", TXT_KILLS); else gr_printf(HUD_SCALE_X(SB_SCORE_LABEL_X),HUD_SCALE_Y(SB_SCORE_Y),"%s:", TXT_SCORE); gr_set_curfont( GAME_FONT ); if ( (Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) ) sprintf(score_str, "%5d", Players[Player_num].net_kills_total); else sprintf(score_str, "%5d", Players[Player_num].score); gr_get_string_size(score_str, &w, &h, &aw ); x = HUD_SCALE_X(SB_SCORE_RIGHT)-w-FSPACX(1); y = HUD_SCALE_Y(SB_SCORE_Y); //erase old score gr_setcolor(BM_XRGB(0,0,0)); gr_rect(x,y,HUD_SCALE_X(SB_SCORE_RIGHT),y+LINE_SPACING); if ( (Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) ) gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); else gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); gr_string(x,y,score_str); } void sb_show_score_added() { int color; int w, h, aw; char score_str[32]; static int x; static int last_score_display = -1; if ( (Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP) ) return; if (score_display == 0) return; gr_set_curfont( GAME_FONT ); score_time -= FrameTime; if (score_time > 0) { if (score_display != last_score_display) last_score_display = score_display; color = f2i(score_time * 20) + 10; if (color < 10) color = 10; if (color > 31) color = 31; if (cheats.enabled) sprintf(score_str, "%s", TXT_CHEATER); else sprintf(score_str, "%5d", score_display); gr_get_string_size(score_str, &w, &h, &aw ); x = HUD_SCALE_X(SB_SCORE_ADDED_RIGHT)-w-FSPACX(1); gr_set_fontcolor(BM_XRGB(0, color, 0),-1 ); gr_string(x, HUD_SCALE_Y(SB_SCORE_ADDED_Y), score_str); } else { //erase old score gr_setcolor(BM_XRGB(0,0,0)); gr_rect(x,HUD_SCALE_Y(SB_SCORE_ADDED_Y),HUD_SCALE_X(SB_SCORE_ADDED_RIGHT),HUD_SCALE_Y(SB_SCORE_ADDED_Y)+LINE_SPACING); score_time = 0; score_display = 0; } } // ----------------------------------------------------------------------------- void play_homing_warning(void) { fix beep_delay; static fix64 Last_warning_beep_time = 0; // Time we last played homing missile warning beep. if (Endlevel_sequence || Player_is_dead) return; if (Players[Player_num].homing_object_dist >= 0) { beep_delay = Players[Player_num].homing_object_dist/128; if (beep_delay > F1_0) beep_delay = F1_0; else if (beep_delay < F1_0/8) beep_delay = F1_0/8; if (GameTime64 - Last_warning_beep_time > beep_delay/2 || Last_warning_beep_time > GameTime64) { digi_play_sample( SOUND_HOMING_WARNING, F1_0 ); Last_warning_beep_time = GameTime64; } } } // ----------------------------------------------------------------------------- void show_homing_warning(void) { if (Endlevel_sequence) { PIGGY_PAGE_IN( Gauges[GAUGE_HOMING_WARNING_OFF] ); hud_bitblt( HOMING_WARNING_X, HOMING_WARNING_Y, &GameBitmaps[Gauges[GAUGE_HOMING_WARNING_OFF].index]); return; } gr_set_current_canvas( NULL ); if (Players[Player_num].homing_object_dist >= 0) { if (GameTime64 & 0x4000) { PIGGY_PAGE_IN(Gauges[GAUGE_HOMING_WARNING_ON]); hud_bitblt( HOMING_WARNING_X, HOMING_WARNING_Y, &GameBitmaps[Gauges[GAUGE_HOMING_WARNING_ON].index]); } else { PIGGY_PAGE_IN(Gauges[GAUGE_HOMING_WARNING_OFF]); hud_bitblt( HOMING_WARNING_X, HOMING_WARNING_Y, &GameBitmaps[Gauges[GAUGE_HOMING_WARNING_OFF].index]); } } else { PIGGY_PAGE_IN(Gauges[GAUGE_HOMING_WARNING_OFF]); hud_bitblt( HOMING_WARNING_X, HOMING_WARNING_Y, &GameBitmaps[Gauges[GAUGE_HOMING_WARNING_OFF].index]); } } void hud_show_homing_warning(void) { if (Players[Player_num].homing_object_dist >= 0) { if (GameTime64 & 0x4000) { gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); gr_string(0x8000, grd_curcanv->cv_bitmap.bm_h-LINE_SPACING,TXT_LOCK); } } } void hud_show_keys(void) { grs_bitmap *blue,*yellow,*red; int y=HUD_SCALE_Y_AR(GameBitmaps[Gauges[GAUGE_LIVES].index].bm_h+2)+FSPACY(1); PIGGY_PAGE_IN(Gauges[KEY_ICON_BLUE]); PIGGY_PAGE_IN(Gauges[KEY_ICON_YELLOW]); PIGGY_PAGE_IN(Gauges[KEY_ICON_RED]); blue=&GameBitmaps[Gauges[KEY_ICON_BLUE].index]; yellow=&GameBitmaps[Gauges[KEY_ICON_YELLOW].index]; red=&GameBitmaps[Gauges[KEY_ICON_RED].index]; if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY) hud_bitblt_free(FSPACX(2),y,HUD_SCALE_X_AR(blue->bm_w),HUD_SCALE_Y_AR(blue->bm_h),blue); if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) hud_bitblt_free(FSPACX(2)+HUD_SCALE_X_AR(blue->bm_w+3),y,HUD_SCALE_X_AR(yellow->bm_w),HUD_SCALE_Y_AR(yellow->bm_h),yellow); if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) hud_bitblt_free(FSPACX(2)+HUD_SCALE_X_AR(blue->bm_w+yellow->bm_w+6),y,HUD_SCALE_X_AR(red->bm_w),HUD_SCALE_Y_AR(red->bm_h),red); } void hud_show_energy(void) { if (PlayerCfg.HudMode<2) { gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); if (Game_mode & GM_MULTI) gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-(LINE_SPACING*5)),"%s: %i", TXT_ENERGY, f2ir(Players[Player_num].energy)); else gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-LINE_SPACING),"%s: %i", TXT_ENERGY, f2ir(Players[Player_num].energy)); } if (Newdemo_state==ND_STATE_RECORDING ) newdemo_record_player_energy(f2ir(Players[Player_num].energy)); } static inline const char *SECONDARY_WEAPON_NAMES_VERY_SHORT(const unsigned u) { switch(u) { default: Int3(); case CONCUSSION_INDEX: return TXT_CONCUSSION; case HOMING_INDEX: return TXT_HOMING; case PROXIMITY_INDEX: return TXT_PROXBOMB; case SMART_INDEX: return TXT_SMART; case MEGA_INDEX: return TXT_MEGA; } } void show_bomb_count(int x,int y,int bg_color,int always_show,int right_align) { int bomb,count,w=0,h=0,aw=0; char txt[5],*t; if (!PlayerCfg.BombGauge) return; bomb = which_bomb(); count = Players[Player_num].secondary_ammo[bomb]; count = min(count,99); //only have room for 2 digits - cheating give 200 if (always_show && count == 0) //no bombs, draw nothing on HUD return; if (count) gr_set_fontcolor(gr_find_closest_color(55,0,0),bg_color); else gr_set_fontcolor(bg_color,bg_color); //erase by drawing in background color snprintf(txt, sizeof(txt), "B:%02d", count); while ((t=strchr(txt,'1')) != NULL) *t = '\x84'; //convert to wide '1' if (right_align) gr_get_string_size(txt, &w, &h, &aw ); gr_string(x-w,y,txt); } void hud_show_weapons_mode(int type,int vertical,int x,int y){ int i,w,h,aw; char weapon_str[10]; if (vertical){ y=y+(LINE_SPACING*4); } if (type==0){ for (i=4;i>=0;i--){ if (Primary_weapon==i) gr_set_fontcolor(BM_XRGB(20,0,0),-1); else{ if (player_has_weapon(i,0) & HAS_WEAPON_FLAG) gr_set_fontcolor(BM_XRGB(0,15,0),-1); else gr_set_fontcolor(BM_XRGB(3,3,3),-1); } switch(i){ case 0: sprintf(weapon_str,"%c%i", (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)?'Q':'L', Players[Player_num].laser_level+1); break; case 1: if (PlayerCfg.CockpitMode[1]==CM_FULL_SCREEN) sprintf(weapon_str,"V%i", f2i(Players[Player_num].primary_ammo[1] * VULCAN_AMMO_SCALE)); else sprintf(weapon_str,"V"); break; case 2: sprintf(weapon_str,"S");break; case 3: sprintf(weapon_str,"P");break; case 4: sprintf(weapon_str,"F");break; } gr_get_string_size(weapon_str, &w, &h, &aw ); if (vertical){ y-=h+FSPACX(2); }else x-=w+FSPACY(3); gr_string(x, y, weapon_str); } } else { for (i=4;i>=0;i--){ if (Secondary_weapon==i) gr_set_fontcolor(BM_XRGB(20,0,0),-1); else{ if (Players[Player_num].secondary_ammo[i]>0) gr_set_fontcolor(BM_XRGB(0,15,0),-1); else gr_set_fontcolor(BM_XRGB(0,6,0),-1); } sprintf(weapon_str,"%i",Players[Player_num].secondary_ammo[i]); gr_get_string_size(weapon_str, &w, &h, &aw ); if (vertical){ y-=h+FSPACX(2); }else x-=w+FSPACY(3); gr_string(x, y, weapon_str); } } gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); } void hud_show_weapons(void) { int y; gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); y = grd_curcanv->cv_bitmap.bm_h; if (Game_mode & GM_MULTI) y -= LINE_SPACING*4; if (PlayerCfg.HudMode==1){ hud_show_weapons_mode(0,0,grd_curcanv->cv_bitmap.bm_w,y-(LINE_SPACING*2)); hud_show_weapons_mode(1,0,grd_curcanv->cv_bitmap.bm_w,y-LINE_SPACING); } else if (PlayerCfg.HudMode==2){ int x1,x2; int w, aw; gr_get_string_size("V1000", &w, &x1, &aw ); gr_get_string_size("0 ", &x2, &x1, &aw); y=grd_curcanv->cv_bitmap.bm_h/1.75; x1=grd_curcanv->cv_bitmap.bm_w/2.1-(FSPACX(40)+w); x2=grd_curcanv->cv_bitmap.bm_w/1.9+(FSPACX(42)+x2); hud_show_weapons_mode(0,1,x1,y); hud_show_weapons_mode(1,1,x2,y); gr_set_fontcolor(BM_XRGB(14,14,23),-1 ); gr_printf(x2, y-(LINE_SPACING*4),"%i", f2ir(Players[Player_num].shields)); gr_set_fontcolor(BM_XRGB(25,18,6),-1 ); gr_printf(x1, y-(LINE_SPACING*4),"%i", f2ir(Players[Player_num].energy)); } else { const char *disp_primary_weapon_name; char weapon_str[32]; int w, h, aw; switch (Primary_weapon) { case 0: if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) sprintf(weapon_str, "%s %s %i", TXT_QUAD, TXT_LASER, Players[Player_num].laser_level+1); else sprintf(weapon_str, "%s %i", TXT_LASER, Players[Player_num].laser_level+1); disp_primary_weapon_name = weapon_str; break; case 1: sprintf(weapon_str, "%s: %i", TXT_W_VULCAN_S, f2i(Players[Player_num].primary_ammo[Primary_weapon] * VULCAN_AMMO_SCALE)); disp_primary_weapon_name = weapon_str; break; case 2: disp_primary_weapon_name = TXT_W_SPREADFIRE_S; break; case 3: disp_primary_weapon_name = TXT_W_PLASMA_S; break; case 4: disp_primary_weapon_name = TXT_W_FUSION_S; break; default: Int3(); disp_primary_weapon_name = ""; break; } gr_get_string_size(disp_primary_weapon_name, &w, &h, &aw ); gr_string(grd_curcanv->cv_bitmap.bm_w-w-FSPACX(1), y-(LINE_SPACING*2), disp_primary_weapon_name);//originally y-8 snprintf(weapon_str, sizeof(weapon_str), "%s %d",SECONDARY_WEAPON_NAMES_VERY_SHORT(Secondary_weapon),Players[Player_num].secondary_ammo[Secondary_weapon]); gr_get_string_size(weapon_str, &w, &h, &aw ); gr_string(grd_curcanv->cv_bitmap.bm_w-w-FSPACX(1), y-LINE_SPACING, weapon_str); show_bomb_count(grd_curcanv->cv_bitmap.bm_w-FSPACX(1), y-(LINE_SPACING*3),-1,1, 1); } if (Primary_weapon == VULCAN_INDEX) if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_primary_ammo(Players[Player_num].primary_ammo[Primary_weapon]); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_secondary_ammo(Players[Player_num].secondary_ammo[Secondary_weapon]); } void hud_show_cloak_invuln(void) { gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { int y = grd_curcanv->cv_bitmap.bm_h; if (Game_mode & GM_MULTI) y -= LINE_SPACING*8; else y -= LINE_SPACING*4; if (Players[Player_num].cloak_time+CLOAK_TIME_MAX-GameTime64 > F1_0*3 || GameTime64 & 0x8000) { gr_printf(FSPACX(1), y, "%s", TXT_CLOAKED); } } if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) { int y = grd_curcanv->cv_bitmap.bm_h; if (Game_mode & GM_MULTI) y -= LINE_SPACING*9; else y -= LINE_SPACING*5; if (Players[Player_num].invulnerable_time+INVULNERABLE_TIME_MAX-GameTime64 > F1_0*4 || GameTime64 & 0x8000) { gr_printf(FSPACX(1), y, "%s", TXT_INVULNERABLE); } } } void hud_show_shield(void) { if (PlayerCfg.HudMode<2) { gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); if ( Players[Player_num].shields >= 0 ) { if (Game_mode & GM_MULTI) gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-(LINE_SPACING*6)),"%s: %i", TXT_SHIELD, f2ir(Players[Player_num].shields)); else gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-(LINE_SPACING*2)),"%s: %i", TXT_SHIELD, f2ir(Players[Player_num].shields)); } else { if (Game_mode & GM_MULTI) gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-(LINE_SPACING*6)),"%s: 0", TXT_SHIELD ); else gr_printf(FSPACX(1), (grd_curcanv->cv_bitmap.bm_h-(LINE_SPACING*2)),"%s: 0", TXT_SHIELD ); } } if (Newdemo_state==ND_STATE_RECORDING ) newdemo_record_player_shields(f2ir(Players[Player_num].shields)); } //draw the icons for number of lives void hud_show_lives() { int x; if (HUD_toolong) return; if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) x = HUD_SCALE_X(7); else x = FSPACX(2); if (Game_mode & GM_MULTI) { gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); gr_printf(x, FSPACY(1), "%s: %d", TXT_DEATHS, Players[Player_num].net_killed_total); } else if (Players[Player_num].lives > 1) { grs_bitmap *bm; PIGGY_PAGE_IN(Gauges[GAUGE_LIVES]); bm=&GameBitmaps[Gauges[GAUGE_LIVES].index]; gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); hud_bitblt_free(x,FSPACY(1),HUD_SCALE_X_AR(bm->bm_w),HUD_SCALE_Y_AR(bm->bm_h),bm); gr_printf(HUD_SCALE_X_AR(bm->bm_w)+x, FSPACY(1), " x %d", Players[Player_num].lives-1); } } void sb_show_lives() { int x,y; grs_bitmap * bm = &GameBitmaps[Gauges[GAUGE_LIVES].index]; x = SB_LIVES_X; y = SB_LIVES_Y; gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); if (Game_mode & GM_MULTI) gr_printf(HUD_SCALE_X(SB_LIVES_LABEL_X),HUD_SCALE_Y(y),"%s:", TXT_DEATHS); else gr_printf(HUD_SCALE_X(SB_LIVES_LABEL_X),HUD_SCALE_Y(y),"%s:", TXT_LIVES); if (Game_mode & GM_MULTI) { char killed_str[20]; int w, h, aw; static int last_x[4] = {SB_SCORE_RIGHT_L,SB_SCORE_RIGHT_L,SB_SCORE_RIGHT_H,SB_SCORE_RIGHT_H}; int x; sprintf(killed_str, "%5d", Players[Player_num].net_killed_total); gr_get_string_size(killed_str, &w, &h, &aw); gr_setcolor(BM_XRGB(0,0,0)); gr_rect(last_x[HIRESMODE], HUD_SCALE_Y(y), HUD_SCALE_X(SB_SCORE_RIGHT), HUD_SCALE_Y(y)+LINE_SPACING); gr_set_fontcolor(BM_XRGB(0,20,0),-1); x = HUD_SCALE_X(SB_SCORE_RIGHT)-w-FSPACX(1); gr_string(x, HUD_SCALE_Y(y), killed_str); last_x[HIRESMODE] = x; return; } //erase old icons gr_setcolor(BM_XRGB(0,0,0)); gr_rect(HUD_SCALE_X(x), HUD_SCALE_Y(y), HUD_SCALE_X(SB_SCORE_RIGHT), HUD_SCALE_Y(y+bm->bm_h)); if (Players[Player_num].lives-1 > 0) { gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); PIGGY_PAGE_IN(Gauges[GAUGE_LIVES]); hud_bitblt_free(HUD_SCALE_X(x),HUD_SCALE_Y(y),HUD_SCALE_X_AR(bm->bm_w),HUD_SCALE_Y_AR(bm->bm_h),bm); gr_printf(HUD_SCALE_X(x)+HUD_SCALE_X_AR(bm->bm_w), HUD_SCALE_Y(y), " x %d", Players[Player_num].lives-1); } } #ifndef RELEASE extern int Piggy_bitmap_cache_next; void show_time() { int secs = f2i(Players[Player_num].time_level) % 60; int mins = f2i(Players[Player_num].time_level) / 60; gr_set_curfont( GAME_FONT ); if (Color_0_31_0 == -1) Color_0_31_0 = BM_XRGB(0,31,0); gr_set_fontcolor(Color_0_31_0, -1 ); gr_printf(SWIDTH-FSPACX(30),GHEIGHT-(LINE_SPACING*11),"%d:%02d", mins, secs); } #endif #define EXTRA_SHIP_SCORE 50000 //get new ship every this many points void add_points_to_score(int points) { int prev_score; score_time += f1_0*2; score_display += points; if (score_time > f1_0*4) score_time = f1_0*4; if (points == 0 || cheats.enabled) return; if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) return; prev_score=Players[Player_num].score; Players[Player_num].score += points; #ifndef SHAREWARE if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_player_score(points); #endif #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI_COOP) multi_send_score(); #endif #endif if (Game_mode & GM_MULTI) return; if (Players[Player_num].score/EXTRA_SHIP_SCORE != prev_score/EXTRA_SHIP_SCORE) { int snd; Players[Player_num].lives += Players[Player_num].score/EXTRA_SHIP_SCORE - prev_score/EXTRA_SHIP_SCORE; powerup_basic(20, 20, 20, 0, TXT_EXTRA_LIFE); if ((snd=Powerup_info[POW_EXTRA_LIFE].hit_sound) > -1 ) digi_play_sample( snd, F1_0 ); } } void add_bonus_points_to_score(int points) { int prev_score; if (points == 0 || cheats.enabled) return; prev_score=Players[Player_num].score; Players[Player_num].score += points; #ifndef SHAREWARE if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_player_score(points); #endif if (Game_mode & GM_MULTI) return; if (Players[Player_num].score/EXTRA_SHIP_SCORE != prev_score/EXTRA_SHIP_SCORE) { int snd; Players[Player_num].lives += Players[Player_num].score/EXTRA_SHIP_SCORE - prev_score/EXTRA_SHIP_SCORE; if ((snd=Powerup_info[POW_EXTRA_LIFE].hit_sound) > -1 ) digi_play_sample( snd, F1_0 ); } } // Decode cockpit bitmap to deccpt and add alpha fields to weapon boxes (as it should have always been) so we later can render sub bitmaps over the window canvases void cockpit_decode_alpha(grs_bitmap *bm) { int i=0,x=0,y=0; static unsigned char *cur=NULL; static short cur_w=0, cur_h=0; static unsigned char cockpitbuf[1024*1024]; // check if we processed this bitmap already if (cur==bm->bm_data && cur_w == bm->bm_w && cur_h == bm->bm_h) return; memset(cockpitbuf,0,1024*1024); // decode the bitmap if (bm->bm_flags & BM_FLAG_RLE){ unsigned char * dbits; unsigned char * sbits; int i, data_offset; data_offset = 1; if (bm->bm_flags & BM_FLAG_RLE_BIG) data_offset = 2; sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)]; dbits = cockpitbuf; for (i=0; i < bm->bm_h; i++ ) { gr_rle_decode(sbits,dbits); if ( bm->bm_flags & BM_FLAG_RLE_BIG ) sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)]))); else sbits += (int)bm->bm_data[4+i]; dbits += bm->bm_w; } } else { memcpy(&cockpitbuf, bm->bm_data, sizeof(unsigned char)*(bm->bm_w*bm->bm_h)); } // add alpha color to the pixels which are inside the window box spans for (y=0;ybm_h;y++) { for (x=0;xbm_w;x++) { if (y >= (HIRESMODE?364:151) && y <= (HIRESMODE?469:193) && ((x >= WinBoxLeft[y-(HIRESMODE?364:151)].l && x <= WinBoxLeft[y-(HIRESMODE?364:151)].r) || (x >=WinBoxRight[y-(HIRESMODE?364:151)].l && x <= WinBoxRight[y-(HIRESMODE?364:151)].r))) cockpitbuf[i]=TRANSPARENCY_COLOR; i++; } } #ifdef OGL ogl_freebmtexture(bm); #endif gr_init_bitmap (&deccpt, 0, 0, 0, bm->bm_w, bm->bm_h, bm->bm_w, cockpitbuf); gr_set_transparent(&deccpt,1); #ifdef OGL ogl_ubitmapm_cs (0, 0, -1, -1, &deccpt, 255, F1_0); // render one time to init the texture #endif if (WinBoxOverlay[0] != NULL) gr_free_sub_bitmap(WinBoxOverlay[0]); if (WinBoxOverlay[1] != NULL) gr_free_sub_bitmap(WinBoxOverlay[1]); WinBoxOverlay[0] = gr_create_sub_bitmap(&deccpt,(PRIMARY_W_BOX_LEFT)-2,(PRIMARY_W_BOX_TOP)-2,(PRIMARY_W_BOX_RIGHT-PRIMARY_W_BOX_LEFT+4),(PRIMARY_W_BOX_BOT-PRIMARY_W_BOX_TOP+4)); WinBoxOverlay[1] = gr_create_sub_bitmap(&deccpt,(SECONDARY_W_BOX_LEFT)-2,(SECONDARY_W_BOX_TOP)-2,(SECONDARY_W_BOX_RIGHT-SECONDARY_W_BOX_LEFT)+4,(SECONDARY_W_BOX_BOT-SECONDARY_W_BOX_TOP)+4); cur = bm->bm_data; cur_w = bm->bm_w; cur_h = bm->bm_h; } void draw_wbu_overlay() { grs_bitmap * bm = &GameBitmaps[cockpit_bitmap[PlayerCfg.CockpitMode[1]].index]; PIGGY_PAGE_IN(cockpit_bitmap[PlayerCfg.CockpitMode[1]]); cockpit_decode_alpha(bm); if (WinBoxOverlay[0] != NULL) hud_bitblt(HUD_SCALE_X(PRIMARY_W_BOX_LEFT-2),HUD_SCALE_Y(PRIMARY_W_BOX_TOP-2),WinBoxOverlay[0]); if (WinBoxOverlay[1] != NULL) hud_bitblt(HUD_SCALE_X(SECONDARY_W_BOX_LEFT-2),HUD_SCALE_Y(SECONDARY_W_BOX_TOP-2),WinBoxOverlay[1]); } void close_gauges() { if (WinBoxOverlay[0] != NULL) gr_free_sub_bitmap(WinBoxOverlay[0]); if (WinBoxOverlay[1] != NULL) gr_free_sub_bitmap(WinBoxOverlay[1]); WinBoxOverlay[0] = NULL; WinBoxOverlay[1] = NULL; } void init_gauges() { old_weapon[0] = old_weapon[1] = -1; } void draw_energy_bar(int energy) { int x1, x2, y; int not_energy = (HIRESMODE?(HUD_SCALE_X(125 - (energy*125)/100)):(HUD_SCALE_X(63 - (energy*63)/100))); double aplitscale=((double)(HUD_SCALE_X(65)/HUD_SCALE_Y(8))/(65/8)); //scale aplitude of energy bar to current resolution aspect // Draw left energy bar PIGGY_PAGE_IN(Gauges[GAUGE_ENERGY_LEFT]); hud_bitblt (HUD_SCALE_X(LEFT_ENERGY_GAUGE_X), HUD_SCALE_Y(LEFT_ENERGY_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_ENERGY_LEFT].index]); gr_setcolor(BM_XRGB(0,0,0)); if (energy < 100) for (y=0; y < HUD_SCALE_Y(LEFT_ENERGY_GAUGE_H); y++) { x1 = HUD_SCALE_X(LEFT_ENERGY_GAUGE_H - 2) - y*(aplitscale); x2 = HUD_SCALE_X(LEFT_ENERGY_GAUGE_H - 2) - y*(aplitscale) + not_energy; if (x2 > HUD_SCALE_X(LEFT_ENERGY_GAUGE_W) - (y*aplitscale)/3) x2 = HUD_SCALE_X(LEFT_ENERGY_GAUGE_W) - (y*aplitscale)/3; if (x2 > x1) gr_uline( i2f(x1+HUD_SCALE_X(LEFT_ENERGY_GAUGE_X)), i2f(y+HUD_SCALE_Y(LEFT_ENERGY_GAUGE_Y)), i2f(x2+HUD_SCALE_X(LEFT_ENERGY_GAUGE_X)), i2f(y+HUD_SCALE_Y(LEFT_ENERGY_GAUGE_Y)) ); } gr_set_current_canvas( NULL ); // Draw right energy bar PIGGY_PAGE_IN(Gauges[GAUGE_ENERGY_RIGHT]); hud_bitblt (HUD_SCALE_X(RIGHT_ENERGY_GAUGE_X), HUD_SCALE_Y(RIGHT_ENERGY_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_ENERGY_RIGHT].index]); if (energy < 100) for (y=0; y < HUD_SCALE_Y(RIGHT_ENERGY_GAUGE_H); y++) { x1 = HUD_SCALE_X(RIGHT_ENERGY_GAUGE_W - RIGHT_ENERGY_GAUGE_H + 2 ) + y*(aplitscale) - not_energy; x2 = HUD_SCALE_X(RIGHT_ENERGY_GAUGE_W - RIGHT_ENERGY_GAUGE_H + 2 ) + y*(aplitscale); if (x1 < (y*aplitscale)/3) x1 = (y*aplitscale)/3; if (x2 > x1) gr_uline( i2f(x1+HUD_SCALE_X(RIGHT_ENERGY_GAUGE_X)), i2f(y+HUD_SCALE_Y(RIGHT_ENERGY_GAUGE_Y)), i2f(x2+HUD_SCALE_X(RIGHT_ENERGY_GAUGE_X)), i2f(y+HUD_SCALE_Y(RIGHT_ENERGY_GAUGE_Y)) ); } gr_set_current_canvas( NULL ); } void draw_shield_bar(int shield) { int bm_num = shield>=100?9:(shield / 10); PIGGY_PAGE_IN(Gauges[GAUGE_SHIELDS+9-bm_num]); hud_bitblt (HUD_SCALE_X(SHIELD_GAUGE_X), HUD_SCALE_Y(SHIELD_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_SHIELDS+9-bm_num].index]); } #define CLOAK_FADE_WAIT_TIME 0x400 void draw_player_ship(int cloak_state,int x, int y) { static fix cloak_fade_timer=0; static int cloak_fade_value=GR_FADE_LEVELS-1; grs_bitmap *bm = NULL; #ifdef NETWORK if (Game_mode & GM_TEAM) { PIGGY_PAGE_IN(Gauges[GAUGE_SHIPS+get_team(Player_num)]); bm = &GameBitmaps[Gauges[GAUGE_SHIPS+get_team(Player_num)].index]; } else #endif { PIGGY_PAGE_IN(Gauges[GAUGE_SHIPS+Player_num]); bm = &GameBitmaps[Gauges[GAUGE_SHIPS+Player_num].index]; } if (cloak_state) { static int step = 0; if (GameTime64-Players[Player_num].cloak_time < F1_0) { step = -2; } else if (Players[Player_num].cloak_time+CLOAK_TIME_MAX-GameTime64 <= F1_0*3) { if (cloak_fade_value >= (GR_FADE_LEVELS-1)) { step = -2; } else if (cloak_fade_value <= 0) { step = 2; } } else { step = 0; cloak_fade_value = 0; } cloak_fade_timer -= FrameTime; while (cloak_fade_timer < 0) { cloak_fade_timer += CLOAK_FADE_WAIT_TIME; cloak_fade_value += step; } if (cloak_fade_value > (GR_FADE_LEVELS-1)) cloak_fade_value = (GR_FADE_LEVELS-1); if (cloak_fade_value <= 0) cloak_fade_value = 0; } else { cloak_fade_timer = 0; cloak_fade_value = GR_FADE_LEVELS-1; } gr_set_current_canvas(NULL); hud_bitblt( HUD_SCALE_X(x), HUD_SCALE_Y(y), bm); gr_settransblend(cloak_fade_value, GR_BLEND_NORMAL); gr_rect(HUD_SCALE_X(x-3), HUD_SCALE_Y(y-3), HUD_SCALE_X(x+bm->bm_w+3), HUD_SCALE_Y(y+bm->bm_h+3)); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); gr_set_current_canvas( NULL ); } #define INV_FRAME_TIME (f1_0/10) //how long for each frame void draw_numerical_display(int shield, int energy) { int sw,sh,saw,ew,eh,eaw; gr_set_curfont( GAME_FONT ); #ifndef OGL PIGGY_PAGE_IN(Gauges[GAUGE_NUMERICAL]); hud_bitblt (HUD_SCALE_X(NUMERICAL_GAUGE_X), HUD_SCALE_Y(NUMERICAL_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_NUMERICAL].index]); #endif // cockpit is not 100% geometric so we need to divide shield and energy X position by 1.951 which should be most accurate // gr_get_string_size is used so we can get the numbers finally in the correct position with sw and ew gr_set_fontcolor(BM_XRGB(14,14,23),-1 ); gr_get_string_size((shield>199)?"200":(shield>99)?"100":(shield>9)?"00":"0",&sw,&sh,&saw); gr_printf( (grd_curscreen->sc_w/1.951)-(sw/2), (grd_curscreen->sc_h/1.365),"%d",shield); gr_set_fontcolor(BM_XRGB(25,18,6),-1 ); gr_get_string_size((energy>199)?"200":(energy>99)?"100":(energy>9)?"00":"0",&ew,&eh,&eaw); gr_printf( (grd_curscreen->sc_w/1.951)-(ew/2), (grd_curscreen->sc_h/1.5),"%d",energy); gr_set_current_canvas( NULL ); } void draw_keys() { gr_set_current_canvas( NULL ); if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY ) { PIGGY_PAGE_IN(Gauges[GAUGE_BLUE_KEY]); hud_bitblt( HUD_SCALE_X(GAUGE_BLUE_KEY_X), HUD_SCALE_Y(GAUGE_BLUE_KEY_Y), &GameBitmaps[Gauges[GAUGE_BLUE_KEY].index]); } else { PIGGY_PAGE_IN(Gauges[GAUGE_BLUE_KEY_OFF]); hud_bitblt( HUD_SCALE_X(GAUGE_BLUE_KEY_X), HUD_SCALE_Y(GAUGE_BLUE_KEY_Y), &GameBitmaps[Gauges[GAUGE_BLUE_KEY_OFF].index]); } if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) { PIGGY_PAGE_IN(Gauges[GAUGE_GOLD_KEY]); hud_bitblt( HUD_SCALE_X(GAUGE_GOLD_KEY_X), HUD_SCALE_Y(GAUGE_GOLD_KEY_Y), &GameBitmaps[Gauges[GAUGE_GOLD_KEY].index]); } else { PIGGY_PAGE_IN(Gauges[GAUGE_GOLD_KEY_OFF]); hud_bitblt( HUD_SCALE_X(GAUGE_GOLD_KEY_X), HUD_SCALE_Y(GAUGE_GOLD_KEY_Y), &GameBitmaps[Gauges[GAUGE_GOLD_KEY_OFF].index]); } if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) { PIGGY_PAGE_IN( Gauges[GAUGE_RED_KEY] ); hud_bitblt( HUD_SCALE_X(GAUGE_RED_KEY_X), HUD_SCALE_Y(GAUGE_RED_KEY_Y), &GameBitmaps[Gauges[GAUGE_RED_KEY].index]); } else { PIGGY_PAGE_IN(Gauges[GAUGE_RED_KEY_OFF]); hud_bitblt( HUD_SCALE_X(GAUGE_RED_KEY_X), HUD_SCALE_Y(GAUGE_RED_KEY_Y), &GameBitmaps[Gauges[GAUGE_RED_KEY_OFF].index]); } } void draw_weapon_info_sub(int info_index,gauge_box *box,int pic_x,int pic_y,char *name,int text_x,int text_y) { grs_bitmap *bm; //clear the window gr_setcolor(BM_XRGB(0,0,0)); gr_rect(HUD_SCALE_X(box->left),HUD_SCALE_Y(box->top),HUD_SCALE_X(box->right),HUD_SCALE_Y(box->bot+1)); bm=&GameBitmaps[Weapon_info[info_index].picture.index]; Assert(bm != NULL); PIGGY_PAGE_IN( Weapon_info[info_index].picture ); hud_bitblt(HUD_SCALE_X(pic_x), HUD_SCALE_Y(pic_y), bm); if (PlayerCfg.HudMode == 0) { gr_set_fontcolor(BM_XRGB(0,20,0),-1 ); gr_string(text_x,text_y,name); // For laser, show level and quadness if (info_index == LASER_INDEX) { gr_printf(text_x,text_y+LINE_SPACING, "%s: %i", TXT_LVL, Players[Player_num].laser_level+1); if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) gr_string(text_x,text_y+(LINE_SPACING*2), TXT_QUAD); } } } void draw_weapon_info(int weapon_type,int weapon_num) { int x,y; #ifdef SHAREWARE if (Newdemo_state==ND_STATE_RECORDING ) newdemo_record_player_weapon(weapon_type, weapon_num); #endif if (weapon_type == 0) { if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { draw_weapon_info_sub(Primary_weapon_to_weapon_info[weapon_num],&gauge_boxes[SB_PRIMARY_BOX],SB_PRIMARY_W_PIC_X,SB_PRIMARY_W_PIC_Y,PRIMARY_WEAPON_NAMES_SHORT(weapon_num),SB_PRIMARY_W_TEXT_X,SB_PRIMARY_W_TEXT_Y); x=SB_PRIMARY_AMMO_X; y=SB_PRIMARY_AMMO_Y; } else { draw_weapon_info_sub(Primary_weapon_to_weapon_info[weapon_num],&gauge_boxes[COCKPIT_PRIMARY_BOX],PRIMARY_W_PIC_X,PRIMARY_W_PIC_Y, PRIMARY_WEAPON_NAMES_SHORT(weapon_num),PRIMARY_W_TEXT_X,PRIMARY_W_TEXT_Y); x=PRIMARY_AMMO_X; y=PRIMARY_AMMO_Y; } } else { if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { draw_weapon_info_sub(Secondary_weapon_to_weapon_info[weapon_num],&gauge_boxes[SB_SECONDARY_BOX],SB_SECONDARY_W_PIC_X,SB_SECONDARY_W_PIC_Y,SECONDARY_WEAPON_NAMES_SHORT(weapon_num),SB_SECONDARY_W_TEXT_X,SB_SECONDARY_W_TEXT_Y); x=SB_SECONDARY_AMMO_X; y=SB_SECONDARY_AMMO_Y; } else { draw_weapon_info_sub(Secondary_weapon_to_weapon_info[weapon_num],&gauge_boxes[COCKPIT_SECONDARY_BOX],SECONDARY_W_PIC_X,SECONDARY_W_PIC_Y,SECONDARY_WEAPON_NAMES_SHORT(weapon_num),SECONDARY_W_TEXT_X,SECONDARY_W_TEXT_Y); x=SECONDARY_AMMO_X; y=SECONDARY_AMMO_Y; } } if (PlayerCfg.HudMode!=0) hud_show_weapons_mode(weapon_type,1,x,y); } void draw_ammo_info(int x,int y,int ammo_count,int primary) { if (PlayerCfg.HudMode!=0) hud_show_weapons_mode(!primary,1,x,y); else { gr_setcolor(BM_XRGB(0,0,0)); gr_set_fontcolor(BM_XRGB(20,0,0),-1 ); gr_printf(x,y,"%03d",ammo_count); } } void draw_primary_ammo_info(int ammo_count) { if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) draw_ammo_info(SB_PRIMARY_AMMO_X,SB_PRIMARY_AMMO_Y,ammo_count,1); else draw_ammo_info(PRIMARY_AMMO_X,PRIMARY_AMMO_Y,ammo_count,1); } void draw_secondary_ammo_info(int ammo_count) { if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) draw_ammo_info(SB_SECONDARY_AMMO_X,SB_SECONDARY_AMMO_Y,ammo_count,0); else draw_ammo_info(SECONDARY_AMMO_X,SECONDARY_AMMO_Y,ammo_count,0); } void draw_weapon_box(int weapon_type,int weapon_num) { gr_set_current_canvas(NULL); gr_set_curfont( GAME_FONT ); if (weapon_num != old_weapon[weapon_type] && weapon_box_states[weapon_type] == WS_SET && (old_weapon[weapon_type] != -1) && !PlayerCfg.HudMode) { weapon_box_states[weapon_type] = WS_FADING_OUT; weapon_box_fade_values[weapon_type]=i2f(GR_FADE_LEVELS-1); } if (old_weapon[weapon_type] == -1) { draw_weapon_info(weapon_type,weapon_num); old_weapon[weapon_type] = weapon_num; weapon_box_states[weapon_type] = WS_SET; } if (weapon_box_states[weapon_type] == WS_FADING_OUT) { draw_weapon_info(weapon_type,old_weapon[weapon_type]); weapon_box_fade_values[weapon_type] -= FrameTime * FADE_SCALE; if (weapon_box_fade_values[weapon_type] <= 0) { weapon_box_states[weapon_type] = WS_FADING_IN; old_weapon[weapon_type] = weapon_num; old_weapon[weapon_type] = weapon_num; weapon_box_fade_values[weapon_type] = 0; } } else if (weapon_box_states[weapon_type] == WS_FADING_IN) { if (weapon_num != old_weapon[weapon_type]) { weapon_box_states[weapon_type] = WS_FADING_OUT; } else { draw_weapon_info(weapon_type,weapon_num); weapon_box_fade_values[weapon_type] += FrameTime * FADE_SCALE; if (weapon_box_fade_values[weapon_type] >= i2f(GR_FADE_LEVELS-1)) { weapon_box_states[weapon_type] = WS_SET; old_weapon[weapon_type] = -1; } } } else { draw_weapon_info(weapon_type, weapon_num); old_weapon[weapon_type] = weapon_num; } if (weapon_box_states[weapon_type] != WS_SET) //fade gauge { int fade_value = f2i(weapon_box_fade_values[weapon_type]); int boxofs = (PlayerCfg.CockpitMode[1]==CM_STATUS_BAR)?SB_PRIMARY_BOX:COCKPIT_PRIMARY_BOX; gr_settransblend(fade_value, GR_BLEND_NORMAL); gr_rect(HUD_SCALE_X(gauge_boxes[boxofs+weapon_type].left),HUD_SCALE_Y(gauge_boxes[boxofs+weapon_type].top),HUD_SCALE_X(gauge_boxes[boxofs+weapon_type].right),HUD_SCALE_Y(gauge_boxes[boxofs+weapon_type].bot)); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } gr_set_current_canvas(NULL); } void draw_weapon_boxes() { draw_weapon_box(0,Primary_weapon); if (weapon_box_states[0] == WS_SET) if (Primary_weapon == VULCAN_INDEX) { if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_primary_ammo(Players[Player_num].primary_ammo[Primary_weapon]); draw_primary_ammo_info(f2i(VULCAN_AMMO_SCALE * Players[Player_num].primary_ammo[Primary_weapon])); } draw_weapon_box(1,Secondary_weapon); if (weapon_box_states[1] == WS_SET) if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_secondary_ammo(Players[Player_num].secondary_ammo[Secondary_weapon]); draw_secondary_ammo_info(Players[Player_num].secondary_ammo[Secondary_weapon]); if(PlayerCfg.HudMode!=0) { draw_primary_ammo_info(f2i(VULCAN_AMMO_SCALE * Players[Player_num].primary_ammo[Primary_weapon])); draw_secondary_ammo_info(Players[Player_num].secondary_ammo[Secondary_weapon]); } } void sb_draw_energy_bar(int energy) { int erase_height,i; int ew, eh, eaw; PIGGY_PAGE_IN(Gauges[SB_GAUGE_ENERGY]); hud_bitblt( HUD_SCALE_X(SB_ENERGY_GAUGE_X), HUD_SCALE_Y(SB_ENERGY_GAUGE_Y), &GameBitmaps[Gauges[SB_GAUGE_ENERGY].index]); erase_height = HUD_SCALE_Y((100 - energy) * SB_ENERGY_GAUGE_H / 100); gr_setcolor( 0 ); for (i=0;i199)?"200":(energy>99)?"100":(energy>9)?"00":"0",&ew,&eh,&eaw); gr_printf((grd_curscreen->sc_w/3)-(ew/2),HUD_SCALE_Y(SB_ENERGY_NUM_Y),"%d",energy); } void sb_draw_shield_num(int shield) { grs_bitmap *bm = &GameBitmaps[cockpit_bitmap[PlayerCfg.CockpitMode[1]].index]; int sw, sh, saw; //draw numbers gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(14,14,23),-1 ); //erase old one PIGGY_PAGE_IN( cockpit_bitmap[PlayerCfg.CockpitMode[1]] ); gr_setcolor(gr_gpixel(bm,SB_SHIELD_NUM_X,SB_SHIELD_NUM_Y-(SM_H(Game_screen_mode)-bm->bm_h))); gr_get_string_size((shield>199)?"200":(shield>99)?"100":(shield>9)?"00":"0",&sw,&sh,&saw); gr_printf((grd_curscreen->sc_w/2.267)-(sw/2),HUD_SCALE_Y(SB_SHIELD_NUM_Y),"%d",shield); } void sb_draw_shield_bar(int shield) { int bm_num = shield>=100?9:(shield / 10); gr_set_current_canvas(NULL); PIGGY_PAGE_IN( Gauges[GAUGE_SHIELDS+9-bm_num] ); hud_bitblt( HUD_SCALE_X(SB_SHIELD_GAUGE_X), HUD_SCALE_Y(SB_SHIELD_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_SHIELDS+9-bm_num].index]); } void sb_draw_keys() { grs_bitmap * bm; int flags = Players[Player_num].flags; gr_set_current_canvas(NULL); bm = &GameBitmaps[Gauges[(flags&PLAYER_FLAGS_BLUE_KEY)?SB_GAUGE_BLUE_KEY:SB_GAUGE_BLUE_KEY_OFF].index]; PIGGY_PAGE_IN(Gauges[(flags&PLAYER_FLAGS_BLUE_KEY)?SB_GAUGE_BLUE_KEY:SB_GAUGE_BLUE_KEY_OFF]); hud_bitblt( HUD_SCALE_X(SB_GAUGE_KEYS_X), HUD_SCALE_Y(SB_GAUGE_BLUE_KEY_Y), bm); bm = &GameBitmaps[Gauges[(flags&PLAYER_FLAGS_GOLD_KEY)?SB_GAUGE_GOLD_KEY:SB_GAUGE_GOLD_KEY_OFF].index]; PIGGY_PAGE_IN(Gauges[(flags&PLAYER_FLAGS_GOLD_KEY)?SB_GAUGE_GOLD_KEY:SB_GAUGE_GOLD_KEY_OFF]); hud_bitblt( HUD_SCALE_X(SB_GAUGE_KEYS_X), HUD_SCALE_Y(SB_GAUGE_GOLD_KEY_Y), bm); bm = &GameBitmaps[Gauges[(flags&PLAYER_FLAGS_RED_KEY)?SB_GAUGE_RED_KEY:SB_GAUGE_RED_KEY_OFF].index]; PIGGY_PAGE_IN(Gauges[(flags&PLAYER_FLAGS_RED_KEY)?SB_GAUGE_RED_KEY:SB_GAUGE_RED_KEY_OFF]); hud_bitblt( HUD_SCALE_X(SB_GAUGE_KEYS_X), HUD_SCALE_Y(SB_GAUGE_RED_KEY_Y), bm); } // Draws invulnerable ship, or maybe the flashing ship, depending on invulnerability time left. void draw_invulnerable_ship() { static fix time=0; gr_set_current_canvas(NULL); if (Players[Player_num].invulnerable_time+INVULNERABLE_TIME_MAX-GameTime64 > F1_0*4 || GameTime64 & 0x8000) { if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { PIGGY_PAGE_IN(Gauges[GAUGE_INVULNERABLE+invulnerable_frame]); hud_bitblt( HUD_SCALE_X(SB_SHIELD_GAUGE_X), HUD_SCALE_Y(SB_SHIELD_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_INVULNERABLE+invulnerable_frame].index]); } else { PIGGY_PAGE_IN(Gauges[GAUGE_INVULNERABLE+invulnerable_frame]); hud_bitblt( HUD_SCALE_X(SHIELD_GAUGE_X), HUD_SCALE_Y(SHIELD_GAUGE_Y), &GameBitmaps[Gauges[GAUGE_INVULNERABLE+invulnerable_frame].index]); } time += FrameTime; while (time > INV_FRAME_TIME) { time -= INV_FRAME_TIME; if (++invulnerable_frame == N_INVULNERABLE_FRAMES) invulnerable_frame=0; } } else if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) sb_draw_shield_bar(f2ir(Players[Player_num].shields)); else draw_shield_bar(f2ir(Players[Player_num].shields)); } extern int Missile_gun; extern int allowed_to_fire_laser(void); extern int allowed_to_fire_missile(void); const rgb player_rgb[] = { {15,15,23}, {27,0,0}, {0,23,0}, {30,11,31}, {31,16,0}, {24,17,6}, {14,21,12}, {29,29,0}, }; typedef struct { sbyte x, y; } xy; //offsets for reticle parts: high-big high-sml low-big low-sml static const xy cross_offsets[4] = { {-8,-5}, {-4,-2}, {-4,-2}, {-2,-1} }; static const xy primary_offsets[4] = { {-30,14}, {-16,6}, {-15,6}, {-8, 2} }; static const xy secondary_offsets[4] = { {-24,2}, {-12,0}, {-12,1}, {-6,-2} }; //draw the reticle void show_reticle(int reticle_type, int secondary_display) { int x,y,size; int laser_ready,missile_ready,laser_ammo,missile_ammo; int cross_bm_num,primary_bm_num,secondary_bm_num; int use_hires_reticle,ofs; x = grd_curcanv->cv_bitmap.bm_w/2; y = grd_curcanv->cv_bitmap.bm_h/2; size = (grd_curcanv->cv_bitmap.bm_h / (32-(PlayerCfg.ReticleSize*4))); laser_ready = allowed_to_fire_laser(); missile_ready = allowed_to_fire_missile(); laser_ammo = player_has_weapon(Primary_weapon,0); missile_ammo = player_has_weapon(Secondary_weapon,1); primary_bm_num = (laser_ready && laser_ammo==HAS_ALL); secondary_bm_num = (missile_ready && missile_ammo==HAS_ALL); if (primary_bm_num && Primary_weapon==LASER_INDEX && (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) primary_bm_num++; if (Secondary_weapon!=CONCUSSION_INDEX && Secondary_weapon!=HOMING_INDEX) secondary_bm_num += 3; else if (secondary_bm_num && !(Missile_gun&1)) secondary_bm_num++; cross_bm_num = ((primary_bm_num > 0) || (secondary_bm_num > 0)); Assert(primary_bm_num <= 2); Assert(secondary_bm_num <= 4); Assert(cross_bm_num <= 1); gr_setcolor(BM_XRGB(PlayerCfg.ReticleRGBA[0],PlayerCfg.ReticleRGBA[1],PlayerCfg.ReticleRGBA[2])); gr_settransblend(PlayerCfg.ReticleRGBA[3], GR_BLEND_NORMAL); switch (reticle_type) { case RET_TYPE_CLASSIC: { grs_bitmap *cross, *primary, *secondary; use_hires_reticle = (HIRESMODE != 0); ofs = (use_hires_reticle?0:2); PIGGY_PAGE_IN(Gauges[RETICLE_CROSS + cross_bm_num]); cross = &GameBitmaps[Gauges[RETICLE_CROSS + cross_bm_num].index]; hud_bitblt_free(x+HUD_SCALE_X_AR(cross_offsets[ofs].x),y+HUD_SCALE_Y_AR(cross_offsets[ofs].y), HUD_SCALE_X_AR(cross->bm_w), HUD_SCALE_Y_AR(cross->bm_h), cross); PIGGY_PAGE_IN(Gauges[RETICLE_PRIMARY + primary_bm_num]); primary = &GameBitmaps[Gauges[RETICLE_PRIMARY + primary_bm_num].index]; hud_bitblt_free(x+HUD_SCALE_X_AR(primary_offsets[ofs].x),y+HUD_SCALE_Y_AR(primary_offsets[ofs].y), HUD_SCALE_X_AR(primary->bm_w), HUD_SCALE_Y_AR(primary->bm_h), primary); PIGGY_PAGE_IN(Gauges[RETICLE_SECONDARY + secondary_bm_num]); secondary = &GameBitmaps[Gauges[RETICLE_SECONDARY + secondary_bm_num].index]; hud_bitblt_free(x+HUD_SCALE_X_AR(secondary_offsets[ofs].x),y+HUD_SCALE_Y_AR(secondary_offsets[ofs].y), HUD_SCALE_X_AR(secondary->bm_w), HUD_SCALE_Y_AR(secondary->bm_h), secondary); break; } case RET_TYPE_CLASSIC_REBOOT: { #ifdef OGL ogl_draw_vertex_reticle(cross_bm_num,primary_bm_num,secondary_bm_num,BM_XRGB(PlayerCfg.ReticleRGBA[0],PlayerCfg.ReticleRGBA[1],PlayerCfg.ReticleRGBA[2]),PlayerCfg.ReticleRGBA[3],PlayerCfg.ReticleSize); #endif break; } case RET_TYPE_X: gr_uline(i2f(x-(size/2)), i2f(y-(size/2)), i2f(x-(size/5)), i2f(y-(size/5))); // top-left gr_uline(i2f(x+(size/2)), i2f(y-(size/2)), i2f(x+(size/5)), i2f(y-(size/5))); // top-right gr_uline(i2f(x-(size/2)), i2f(y+(size/2)), i2f(x-(size/5)), i2f(y+(size/5))); // bottom-left gr_uline(i2f(x+(size/2)), i2f(y+(size/2)), i2f(x+(size/5)), i2f(y+(size/5))); // bottom-right if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)-(size/5)), i2f(y-(size/2)), i2f(x-(size/5)-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)+(size/5)), i2f(y-(size/2)), i2f(x+(size/5)+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x+(size/2)), i2f(y+(size/2)+(size/5)), i2f(x+(size/5)), i2f(y+(size/5)+(size/5))); break; case RET_TYPE_DOT: gr_disk(i2f(x),i2f(y),i2f(size/5)); if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)-(size/5)), i2f(y-(size/2)), i2f(x-(size/5)-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)+(size/5)), i2f(y-(size/2)), i2f(x+(size/5)+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x), i2f(y+(size/2)+(size/5)), i2f(x), i2f(y+(size/5)+(size/5))); break; case RET_TYPE_CIRCLE: gr_ucircle(i2f(x),i2f(y),i2f(size/4)); if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)-(size/5)), i2f(y-(size/2)), i2f(x-(size/5)-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)+(size/5)), i2f(y-(size/2)), i2f(x+(size/5)+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x), i2f(y+(size/2)+(size/5)), i2f(x), i2f(y+(size/5)+(size/5))); break; case RET_TYPE_CROSS_V1: gr_uline(i2f(x),i2f(y-(size/2)),i2f(x),i2f(y+(size/2)+1)); // horiz gr_uline(i2f(x-(size/2)),i2f(y),i2f(x+(size/2)+1),i2f(y)); // vert if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)), i2f(y-(size/2)), i2f(x-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)), i2f(y-(size/2)), i2f(x+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x-(size/2)), i2f(y+(size/2)), i2f(x-(size/5)), i2f(y+(size/5))); break; case RET_TYPE_CROSS_V2: gr_uline(i2f(x), i2f(y-(size/2)), i2f(x), i2f(y-(size/6))); // vert-top gr_uline(i2f(x), i2f(y+(size/2)), i2f(x), i2f(y+(size/6))); // vert-bottom gr_uline(i2f(x-(size/2)), i2f(y), i2f(x-(size/6)), i2f(y)); // horiz-left gr_uline(i2f(x+(size/2)), i2f(y), i2f(x+(size/6)), i2f(y)); // horiz-right if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)), i2f(y-(size/2)), i2f(x-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)), i2f(y-(size/2)), i2f(x+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x-(size/2)), i2f(y+(size/2)), i2f(x-(size/5)), i2f(y+(size/5))); break; case RET_TYPE_ANGLE: gr_uline(i2f(x),i2f(y),i2f(x),i2f(y+(size/2))); // vert gr_uline(i2f(x),i2f(y),i2f(x+(size/2)),i2f(y)); // horiz if (secondary_display && secondary_bm_num == 1) gr_uline(i2f(x-(size/2)), i2f(y-(size/2)), i2f(x-(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 2) gr_uline(i2f(x+(size/2)), i2f(y-(size/2)), i2f(x+(size/5)), i2f(y-(size/5))); else if (secondary_display && secondary_bm_num == 4) gr_uline(i2f(x-(size/2)), i2f(y+(size/2)), i2f(x-(size/5)), i2f(y+(size/5))); break; case RET_TYPE_NONE: break; default: break; } gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } void show_mousefs_indicator(int mx, int my, int mz, int x, int y, int size) { int axscale = (MOUSEFS_DELTA_RANGE*2)/size, xaxpos = x+(mx/axscale), yaxpos = y+(my/axscale), zaxpos = y+(mz/axscale); gr_setcolor(BM_XRGB(PlayerCfg.ReticleRGBA[0],PlayerCfg.ReticleRGBA[1],PlayerCfg.ReticleRGBA[2])); gr_settransblend(PlayerCfg.ReticleRGBA[3], GR_BLEND_NORMAL); gr_uline(i2f(xaxpos), i2f(y-(size/2)), i2f(xaxpos), i2f(y-(size/4))); gr_uline(i2f(xaxpos), i2f(y+(size/2)), i2f(xaxpos), i2f(y+(size/4))); gr_uline(i2f(x-(size/2)), i2f(yaxpos), i2f(x-(size/4)), i2f(yaxpos)); gr_uline(i2f(x+(size/2)), i2f(yaxpos), i2f(x+(size/4)), i2f(yaxpos)); gr_uline(i2f(x+(size/2)+HUD_SCALE_X_AR(2)), i2f(y), i2f(x+(size/2)+HUD_SCALE_X_AR(2)), i2f(zaxpos)); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } #ifdef NETWORK void hud_show_kill_list() { int n_players,player_list[MAX_PLAYERS]; int n_left,i,x0,x1,y,save_y; if (Show_kill_list_timer > 0) { Show_kill_list_timer -= FrameTime; if (Show_kill_list_timer < 0) Show_kill_list = 0; } gr_set_curfont( GAME_FONT ); n_players = multi_get_kill_list(player_list); if (Show_kill_list == 3) n_players = 2; if (n_players <= 4) n_left = n_players; else n_left = (n_players+1)/2; x0 = FSPACX(1); x1 = FSPACX(43); if (Game_mode & GM_MULTI_COOP) x1 = FSPACX(31); save_y = y = grd_curcanv->cv_bitmap.bm_h - n_left*(LINE_SPACING); if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) { save_y = y -= FSPACX(6); if (Game_mode & GM_MULTI_COOP) x1 = FSPACX(33); else x1 = FSPACX(43); } for (i=0;i=n_left) { if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) x0 = grd_curcanv->cv_bitmap.bm_w - FSPACX(53); else x0 = grd_curcanv->cv_bitmap.bm_w - FSPACX(60); if (Game_mode & GM_MULTI_COOP) x1 = grd_curcanv->cv_bitmap.bm_w - FSPACX(27); else x1 = grd_curcanv->cv_bitmap.bm_w - FSPACX(15); // Right edge of name, change this for width problems if (i==n_left) y = save_y; if (Netgame.KillGoal || Netgame.PlayTimeAllowed) x1-=FSPACX(18); } else if (Netgame.KillGoal || Netgame.PlayTimeAllowed) { x1 = FSPACX(43); x1 -=FSPACX(18); } if (Show_kill_list == 3) player_num = i; else player_num = player_list[i]; if (Show_kill_list == 1 || Show_kill_list==2) { int color; if (Players[player_num].connected != CONNECT_PLAYING) gr_set_fontcolor(BM_XRGB(12, 12, 12), -1); else if (Game_mode & GM_TEAM) { color = get_team(player_num); gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 ); } else { color = player_num; gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 ); } } else { gr_set_fontcolor(BM_XRGB(player_rgb[player_num].r,player_rgb[player_num].g,player_rgb[player_num].b),-1 ); } if (Show_kill_list == 3) strcpy(name, Netgame.team_name[i]); else if (Game_mode & GM_BOUNTY && player_num == Bounty_target && GameTime64&0x10000) strcpy(name,"[TARGET]"); else strcpy(name,Players[player_num].callsign); // Note link to above if!! gr_get_string_size(name,&sw,&sh,&aw); while (sw > (x1-x0-FSPACX(2))) { name[strlen(name)-1]=0; gr_get_string_size(name,&sw,&sh,&aw); } gr_printf(x0,y,"%s",name); if (Show_kill_list==2) { if (Players[player_num].net_killed_total+Players[player_num].net_kills_total==0) gr_string (x1,y,"NA"); else gr_printf (x1,y,"%d%%",(int)((float)((float)Players[player_num].net_kills_total/((float)Players[player_num].net_killed_total+(float)Players[player_num].net_kills_total))*100.0)); } else if (Show_kill_list == 3) gr_printf(x1,y,"%3d",team_kills[i]); else if (Game_mode & GM_MULTI_COOP) gr_printf(x1,y,"%-6d",Players[player_num].score); else if (Netgame.PlayTimeAllowed || Netgame.KillGoal) gr_printf(x1,y,"%3d(%d)",Players[player_num].net_kills_total,Players[player_num].KillGoalCount); else gr_printf(x1,y,"%3d",Players[player_num].net_kills_total); y += LINE_SPACING; } } #endif //returns true if viewer can see object int see_object(int objnum) { fvi_query fq; int hit_type; fvi_info hit_data; //see if we can see this player fq.p0 = &Viewer->pos; fq.p1 = &Objects[objnum].pos; fq.rad = 0; fq.thisobjnum = Viewer - Objects; fq.flags = FQ_TRANSWALL | FQ_CHECK_OBJS | FQ_GET_SEGLIST; fq.startseg = Viewer->segnum; fq.ignore_obj_list = NULL; hit_type = find_vector_intersection(&fq, &hit_data); return (hit_type == HIT_OBJECT && hit_data.hit_object == objnum); } void show_HUD_names() { int is_friend = 0, show_friend_name = 0, show_enemy_name = 0, show_name = 0, show_typing = 0, show_indi = 0, pnum = 0, objnum = 0; for (pnum=0;pnum Highest_object_index) //not in list, thus not visible continue; //..so don't show name } else objnum = Players[pnum].objnum; if ((show_name || show_typing || show_indi) && see_object(objnum)) { g3s_point player_point; g3_rotate_point(&player_point,&Objects[objnum].pos); if (player_point.p3_codes == 0) //on screen { g3_project_point(&player_point); if (!(player_point.p3_flags & PF_OVERFLOW)) { fix x,y,dx,dy; char s[CALLSIGN_LEN+10]; int w, h, aw, x1, y1, color_num; x = player_point.p3_sx; y = player_point.p3_sy; dy = -fixmuldiv(fixmul(Objects[objnum].size,Matrix_scale.y),i2f(grd_curcanv->cv_bitmap.bm_h)/2,player_point.p3_z); dx = fixmul(dy,grd_curscreen->sc_aspect); color_num = (Game_mode & GM_TEAM)?get_team(pnum):pnum; memset(&s, '\0', CALLSIGN_LEN+10); /* Set the text to show */ if( Game_mode & GM_BOUNTY && pnum == Bounty_target ) strncpy( s, "Target", 6 ); else if (show_name) snprintf( s, sizeof(s), "%s", Players[pnum].callsign ); if (show_typing && multi_sending_message[pnum]) { if (s[0]) strncat( s, ", typing", 8); else strncpy( s, "Typing", 6 ); } if (s[0]) { gr_get_string_size(s, &w, &h, &aw); gr_set_fontcolor(BM_XRGB(player_rgb[color_num].r,player_rgb[color_num].g,player_rgb[color_num].b),-1 ); x1 = f2i(x)-w/2; y1 = f2i(y-dy)+FSPACY(1); gr_string (x1, y1, s); } /* Draw box on HUD */ if (show_indi) { fix w,h; w = dx/4; h = dy/4; // if (Game_mode & GM_CAPTURE) // gr_setcolor((get_team(pnum) == TEAM_BLUE)?BM_XRGB(31,0,0):BM_XRGB(0,0,31)); // else if (Game_mode & GM_HOARD) // { // if (Game_mode & GM_TEAM) // gr_setcolor((get_team(pnum) == TEAM_RED)?BM_XRGB(31,0,0):BM_XRGB(0,0,31)); // else // gr_setcolor(BM_XRGB(0,31,0)); // } // else if( Game_mode & GM_BOUNTY ) gr_setcolor( BM_XRGB( player_rgb[pnum].r, player_rgb[pnum].g, player_rgb[pnum].b ) ); gr_line(x+dx-w,y-dy,x+dx,y-dy); gr_line(x+dx,y-dy,x+dx,y-dy+h); gr_line(x-dx,y-dy,x-dx+w,y-dy); gr_line(x-dx,y-dy,x-dx,y-dy+h); gr_line(x+dx-w,y+dy,x+dx,y+dy); gr_line(x+dx,y+dy,x+dx,y+dy-h); gr_line(x-dx,y+dy,x-dx+w,y+dy); gr_line(x-dx,y+dy,x-dx,y+dy-h); } } } } } } //draw all the things on the HUD void draw_hud() { if (PlayerCfg.HudMode==3) // no hud, "immersion mode" return; // Cruise speed if ( Player_num > -1 && Viewer->type==OBJ_PLAYER && Viewer->id==Player_num && PlayerCfg.CockpitMode[1] != CM_REAR_VIEW) { int x = FSPACX(1); int y = grd_curcanv->cv_bitmap.bm_h; gr_set_curfont( GAME_FONT ); gr_set_fontcolor( BM_XRGB(0, 31, 0), -1 ); if (Cruise_speed > 0) { if (PlayerCfg.CockpitMode[1]==CM_FULL_SCREEN) { if (Game_mode & GM_MULTI) y -= LINE_SPACING * 10; else y -= LINE_SPACING * 6; } else if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { if (Game_mode & GM_MULTI) y -= LINE_SPACING * 6; else y -= LINE_SPACING * 1; } else { if (Game_mode & GM_MULTI) y -= LINE_SPACING * 7; else y -= LINE_SPACING * 2; } gr_printf( x, y, "%s %2d%%", TXT_CRUISE, f2i(Cruise_speed) ); } } // Show score so long as not in rearview if ( !Rear_view && PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW && PlayerCfg.CockpitMode[1]!=CM_STATUS_BAR) { hud_show_score(); if (score_time) hud_show_score_added(); } if ( !Rear_view && PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW) hud_show_timer_count(); // Show other stuff if not in rearview or letterbox. if (!Rear_view && PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW) { show_HUD_names(); if (PlayerCfg.CockpitMode[1]==CM_STATUS_BAR || PlayerCfg.CockpitMode[1]==CM_FULL_SCREEN) hud_show_homing_warning(); if (PlayerCfg.CockpitMode[1]==CM_FULL_SCREEN) { hud_show_energy(); hud_show_shield(); hud_show_weapons(); if (!PCSharePig) hud_show_keys(); hud_show_cloak_invuln(); if (Newdemo_state==ND_STATE_RECORDING) newdemo_record_player_flags(Players[Player_num].flags); } #ifndef RELEASE if (!(Game_mode&GM_MULTI && Show_kill_list)) show_time(); #endif HUD_render_message_frame(); if (PlayerCfg.CockpitMode[1]!=CM_STATUS_BAR) hud_show_lives(); if (Game_mode&GM_MULTI && Show_kill_list) hud_show_kill_list(); if (PlayerCfg.CockpitMode[1] != CM_LETTERBOX) show_reticle(PlayerCfg.ReticleType, 1); if (PlayerCfg.CockpitMode[1] != CM_LETTERBOX && Newdemo_state != ND_STATE_PLAYBACK && PlayerCfg.MouseFlightSim && PlayerCfg.MouseFSIndicator) show_mousefs_indicator(Controls.raw_mouse_axis[0], Controls.raw_mouse_axis[1], Controls.raw_mouse_axis[2], GWIDTH/2, GHEIGHT/2, GHEIGHT/4); } if (Rear_view && PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW) { HUD_render_message_frame(); gr_set_curfont( GAME_FONT ); gr_set_fontcolor(BM_XRGB(0,31,0),-1 ); gr_string(0x8000,GHEIGHT-LINE_SPACING,TXT_REAR_VIEW); } } //print out some player statistics void render_gauges() { int energy = f2ir(Players[Player_num].energy); int shields = f2ir(Players[Player_num].shields); int cloak = ((Players[Player_num].flags&PLAYER_FLAGS_CLOAKED) != 0); Assert(PlayerCfg.CockpitMode[1]==CM_FULL_COCKPIT || PlayerCfg.CockpitMode[1]==CM_STATUS_BAR); if (shields < 0 ) shields = 0; gr_set_current_canvas(NULL); gr_set_curfont( GAME_FONT ); if (Newdemo_state == ND_STATE_RECORDING) if (Players[Player_num].homing_object_dist >= 0) newdemo_record_homing_distance(Players[Player_num].homing_object_dist); draw_weapon_boxes(); if (PlayerCfg.CockpitMode[1] == CM_FULL_COCKPIT) { if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_player_energy(energy); draw_energy_bar(energy); draw_numerical_display(shields, energy); if (!PlayerCfg.HudMode) show_bomb_count(HUD_SCALE_X(BOMB_COUNT_X), HUD_SCALE_Y(BOMB_COUNT_Y), gr_find_closest_color(0, 0, 0), 0, 0); draw_player_ship(cloak, SHIP_GAUGE_X, SHIP_GAUGE_Y); if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) draw_invulnerable_ship(); else draw_shield_bar(shields); draw_numerical_display(shields, energy); if (Newdemo_state == ND_STATE_RECORDING) { newdemo_record_player_shields(shields); newdemo_record_player_flags(Players[Player_num].flags); } draw_keys(); show_homing_warning(); draw_wbu_overlay(); } else if (PlayerCfg.CockpitMode[1] == CM_STATUS_BAR) { if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_player_energy(energy); sb_draw_energy_bar(energy); if (!PlayerCfg.HudMode) show_bomb_count(HUD_SCALE_X(SB_BOMB_COUNT_X), HUD_SCALE_Y(SB_BOMB_COUNT_Y), gr_find_closest_color(0, 0, 0), 0, 0); draw_player_ship(cloak, SB_SHIP_GAUGE_X, SB_SHIP_GAUGE_Y); if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) draw_invulnerable_ship(); else sb_draw_shield_bar(shields); sb_draw_shield_num(shields); if (Newdemo_state==ND_STATE_RECORDING) { newdemo_record_player_shields(shields); newdemo_record_player_flags(Players[Player_num].flags); } sb_draw_keys(); sb_show_lives(); if ((Game_mode&GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) { sb_show_score(); } else { sb_show_score(); sb_show_score_added(); } } else draw_player_ship(cloak, SB_SHIP_GAUGE_X, SB_SHIP_GAUGE_Y); } // --------------------------------------------------------------------------------------------------------- // Call when picked up a laser powerup. // If laser is active, set old_weapon[0] to -1 to force redraw. void update_laser_weapon_info(void) { if (old_weapon[0] == 0) old_weapon[0] = -1; } dxx-rebirth-0.58.1-d1x/main/gauges.h000066400000000000000000000050401217717257200171210ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes and defines for gauges * */ #ifndef _GAUGES_H #define _GAUGES_H #include "fix.h" #include "gr.h" #include "piggy.h" #include "hudmsg.h" //from gauges.c #define MAX_GAUGE_BMS_PC 80 // increased from 56 to 80 by a very unhappy MK on 10/24/94. #define MAX_GAUGE_BMS_MAC 85 #define MAX_GAUGE_BMS (MacPig ? MAX_GAUGE_BMS_MAC : MAX_GAUGE_BMS_PC) extern bitmap_index Gauges[MAX_GAUGE_BMS_MAC]; // Array of all gauge bitmaps. extern void add_points_to_score(); extern void add_bonus_points_to_score(); void render_gauges(void); void init_gauges(void); void close_gauges(void); void cockpit_decode_alpha(grs_bitmap *bm); void show_mousefs_indicator(int mx, int my, int mz, int x, int y, int size); extern void draw_hud(); // draw all the HUD stuff extern void player_dead_message(void); //extern void say_afterburner_status(void); // from testgaug.c extern void update_laser_weapon_info(void); extern void play_homing_warning(void); typedef struct { ubyte r,g,b; } rgb; extern const rgb player_rgb[]; #define GAUGE_HUD_NUMMODES 4 typedef struct span { int l,r; } span; extern span weapon_window_left[],weapon_window_left_hires[],weapon_window_right[],weapon_window_right_hires[]; #define WinBoxLeft (HIRESMODE?weapon_window_left_hires:weapon_window_left) #define WinBoxRight (HIRESMODE?weapon_window_right_hires:weapon_window_right) // defines for the reticle(s) #define RET_TYPE_CLASSIC 0 #define RET_TYPE_CLASSIC_REBOOT 1 #define RET_TYPE_NONE 2 #define RET_TYPE_X 3 #define RET_TYPE_DOT 4 #define RET_TYPE_CIRCLE 5 #define RET_TYPE_CROSS_V1 6 #define RET_TYPE_CROSS_V2 7 #define RET_TYPE_ANGLE 8 #define RET_COLOR_DEFAULT_R 0 #define RET_COLOR_DEFAULT_G 32 #define RET_COLOR_DEFAULT_B 0 #define RET_COLOR_DEFAULT_A 0 #endif dxx-rebirth-0.58.1-d1x/main/hash.h000066400000000000000000000033651217717257200166010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/hash.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:43:14 $ * * . * * $Log: hash.h,v $ * Revision 1.1.1.1 2006/03/17 19:43:14 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:12:28 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:26:46 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.2 1994/05/03 16:45:24 john * Added hash table lookup to speed up loading. * * Revision 1.1 1994/05/03 11:35:16 john * Initial revision * * */ #ifndef _HASH_H #define _HASH_H typedef struct hashtable { int bitsize; int and_mask; int size; int nitems; char **key; int *value; } hashtable; int hashtable_init( hashtable *ht, int size ); void hashtable_free( hashtable *ht ); int hashtable_search( hashtable *ht, char *key ); void hashtable_insert( hashtable *ht, char *key, int value ); #endif dxx-rebirth-0.58.1-d1x/main/hostage.c000066400000000000000000000101571217717257200173000ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code to render and manipulate hostages * */ #include #include #include #include "dxxerror.h" #include "3d.h" #include "inferno.h" #include "object.h" #include "game.h" #include "player.h" #include "fireball.h" #include "gauges.h" #include "hostage.h" #include "lighting.h" #include "sounds.h" #include "vclip.h" #include "newdemo.h" #include "text.h" #include "piggy.h" #include "playsave.h" //------------- Globaly used hostage variables -------------------------------------------------- int N_hostage_types = 0; // Number of hostage types int Hostage_vclip_num[MAX_HOSTAGE_TYPES]; // vclip num for each tpye of hostage hostage_data Hostages[MAX_HOSTAGES]; // Data for each hostage in mine //-------------- Renders a hostage ---------------------------------------------------------------- void draw_hostage(object *obj) { Assert( obj->id < MAX_HOSTAGES ); draw_object_tmap_rod(obj, Vclip[obj->rtype.vclip_info.vclip_num].frames[obj->rtype.vclip_info.framenum], 1); } //------------- Called once when a hostage is rescued ------------------------------------------ void hostage_rescue( int hostage_number ) { if ( (hostage_number<0) || (hostage_number>=MAX_HOSTAGES) ) { Int3(); // Get John! return; } PALETTE_FLASH_ADD(0, 0, 25); //small blue flash Players[Player_num].hostages_on_board++; // Do an audio effect if (Newdemo_state != ND_STATE_PLAYBACK) digi_play_sample(SOUND_HOSTAGE_RESCUED, F1_0); HUD_init_message_literal(HM_DEFAULT, TXT_HOSTAGE_RESCUED); } #define LINEBUF_SIZE 100 //------------------- Useful macros and variables --------------- int hostage_is_valid( int hostage_num ) { if ( hostage_num < 0 ) return 0; if ( hostage_num >= MAX_HOSTAGES ) return 0; if ( Hostages[hostage_num].objnum < 0 ) return 0; if ( Hostages[hostage_num].objnum > Highest_object_index ) return 0; if ( Objects[Hostages[hostage_num].objnum].type != OBJ_HOSTAGE ) return 0; if ( Objects[Hostages[hostage_num].objnum].signature != Hostages[hostage_num].objsig ) return 0; if ( Objects[Hostages[hostage_num].objnum].id != hostage_num) return 0; return 1; } int hostage_object_is_valid( int objnum ) { if ( objnum < 0 ) return 0; if ( objnum > Highest_object_index ) return 0; if ( Objects[objnum].type != OBJ_HOSTAGE ) return 0; return hostage_is_valid(Objects[objnum].id); } static int hostage_get_next_slot() { int i; for (i=0; i -1 ); Hostages[i].objnum = objnum; Hostages[i].objsig = Objects[objnum].signature; //Hostages[i].type = 0; //Hostages[i].sound_num = -1; Objects[objnum].id = i; } void hostage_init_all() { int i; // Initialize all their values... for (i=0; i #include #include #include "hudmsg.h" #include "pstypes.h" #include "u_mem.h" #include "strutil.h" #include "console.h" #include "inferno.h" #include "game.h" #include "screens.h" #include "gauges.h" #include "physics.h" #include "dxxerror.h" #include "menu.h" // For the font. #include "collide.h" #include "newdemo.h" #include "player.h" #include "gamefont.h" #include "wall.h" #include "screens.h" #include "text.h" #include "laser.h" #include "args.h" #include "playsave.h" typedef struct hudmsg { fix time; char message[HUD_MESSAGE_LENGTH+1]; } hudmsg; hudmsg HUD_messages[HUD_MAX_NUM_STOR]; static int HUD_nmessages = 0; int HUD_toolong = 0; static int HUD_color = -1; static int HUD_init_message_literal_worth_showing(int class_flag, const char *message); void HUD_clear_messages() { HUD_nmessages = 0; HUD_toolong = 0; memset(&HUD_messages, 0, sizeof(struct hudmsg)*HUD_MAX_NUM_STOR); HUD_color = -1; } // ---------------------------------------------------------------------------- // Writes a message on the HUD and checks its timer. void HUD_render_message_frame() { int i,j,y; HUD_toolong = 0; if (( HUD_nmessages < 0 ) || (HUD_nmessages > HUD_MAX_NUM_STOR)) Int3(); // Get Rob! if (HUD_nmessages < 1 ) return; for (i = 0; i < HUD_nmessages; i++) { HUD_messages[i].time -= FrameTime; // message expired - remove if (HUD_messages[i].time <= 0) { for (j = i; j < HUD_nmessages; j++) { if (j+1 < HUD_nmessages) memcpy(&HUD_messages[j], &HUD_messages[j+1], sizeof(struct hudmsg)); else memset(&HUD_messages[j], 0, sizeof(struct hudmsg)); } HUD_nmessages--; } } // display last $HUD_MAX_NUM_DISP messages on the list if (HUD_nmessages > 0 ) { int startmsg = ((HUD_nmessages-HUD_MAX_NUM_DISP<0)?0:HUD_nmessages-HUD_MAX_NUM_DISP); if (HUD_color == -1) HUD_color = BM_XRGB(0,28,0); gr_set_curfont( GAME_FONT ); y = FSPACY(1); for (i=startmsg; i 38) HUD_toolong = 1; gr_string(0x8000,y, &HUD_messages[i].message[0] ); y += LINE_SPACING; } } gr_set_curfont( GAME_FONT ); } static int is_worth_showing(int class_flag) { if (PlayerCfg.NoRedundancy && (class_flag & HM_REDUNDANT)) return 0; if (PlayerCfg.MultiMessages && (Game_mode & GM_MULTI) && !(class_flag & HM_MULTI)) return 0; return 1; } // Call to flash a message on the HUD. Returns true if message drawn. // (message might not be drawn if previous message was same) int HUD_init_message_va(int class_flag, const char * format, va_list args) { if (!is_worth_showing(class_flag)) return 0; #ifndef macintosh char message[HUD_MESSAGE_LENGTH+1] = ""; #else char message[1024] = ""; #endif #ifndef macintosh vsnprintf(message, sizeof(char)*HUD_MESSAGE_LENGTH, format, args); #else vsprintf(message, format, args); #endif return HUD_init_message_literal_worth_showing(class_flag, message); } static int HUD_init_message_literal_worth_showing(int class_flag, const char *message) { int i, j; // check if message is already in list and bail out if so if (HUD_nmessages > 0) { // if "normal" message, only check if it's the same at the most recent one, if marked as "may duplicate" check whole list for (i = ((class_flag & HM_MAYDUPL)?0:HUD_nmessages-1); i < HUD_nmessages; i++) { if (!d_strnicmp(message, HUD_messages[i].message, sizeof(char)*HUD_MESSAGE_LENGTH)) { HUD_messages[i].time = F1_0*2; // keep redundant message in list if (i >= HUD_nmessages-HUD_MAX_NUM_DISP) // if redundant message on display, update them all for (i = (HUD_nmessages-HUD_MAX_NUM_DISP<0?0:HUD_nmessages-HUD_MAX_NUM_DISP), j = 1; i < HUD_nmessages; i++, j++) HUD_messages[i].time = F1_0*(j*2); return 0; } } } if (HUD_nmessages >= HUD_MAX_NUM_STOR) { HUD_nmessages = HUD_MAX_NUM_STOR; // unnecessary but just in case it might be bigger... which is impossible for (i = 0; i < HUD_nmessages-1; i++) { memcpy(&HUD_messages[i], &HUD_messages[i+1], sizeof(struct hudmsg)); } } else { HUD_nmessages++; } snprintf(HUD_messages[HUD_nmessages-1].message, sizeof(char)*HUD_MESSAGE_LENGTH, "%s", message); if (HUD_nmessages-HUD_MAX_NUM_DISP < 0) HUD_messages[HUD_nmessages-1].time = F1_0*3; // one message - display 3 secs else for (i = HUD_nmessages-HUD_MAX_NUM_DISP, j = 1; i < HUD_nmessages; i++, j++) // multiple messages - display 2 seconds each HUD_messages[i].time = F1_0*(j*2); if (HUD_color == -1) HUD_color = BM_XRGB(0,28,0); con_printf(CON_HUD, "%s\n", message); if (Newdemo_state == ND_STATE_RECORDING ) newdemo_record_hud_message( message ); return 1; } int HUD_init_message(int class_flag, const char * format, ... ) { int ret; va_list args; va_start(args, format); ret = HUD_init_message_va(class_flag, format, args); va_end(args); return ret; } int HUD_init_message_literal(int class_flag, const char *str) { if (!is_worth_showing(class_flag)) return 0; return HUD_init_message_literal_worth_showing(class_flag, str); } void player_dead_message(void) { if (Player_exploded) { if ( Players[Player_num].lives < 2 ) { int x, y, w, h, aw; gr_set_curfont( HUGE_FONT ); gr_get_string_size( TXT_GAME_OVER, &w, &h, &aw ); w += 20; h += 8; x = (grd_curcanv->cv_bitmap.bm_w - w ) / 2; y = (grd_curcanv->cv_bitmap.bm_h - h ) / 2; gr_settransblend(14, GR_BLEND_NORMAL); gr_setcolor( BM_XRGB(0,0,0) ); gr_rect( x, y, x+w, y+h ); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); gr_string(0x8000, (GHEIGHT - h)/2 + h/8, TXT_GAME_OVER ); } gr_set_curfont( GAME_FONT ); if (HUD_color == -1) HUD_color = BM_XRGB(0,28,0); gr_set_fontcolor( HUD_color, -1); gr_string(0x8000, GHEIGHT-LINE_SPACING, TXT_PRESS_ANY_KEY); } } dxx-rebirth-0.58.1-d1x/main/hudmsg.h000066400000000000000000000015521217717257200171410ustar00rootroot00000000000000#ifndef _HUD_MSG_H #define _HUD_MSG_H #include #define HUD_MESSAGE_LENGTH 150 #define HUD_MAX_NUM_DISP 4 #define HUD_MAX_NUM_STOR 20 // classes - expanded whenever needed #define HM_DEFAULT 1 // just some normal message #define HM_MULTI 2 // a message related to multiplayer (game and player messages) #define HM_REDUNDANT 4 // "you already have..."-type messages. stuff a player is able to supress #define HM_MAYDUPL 8 // messages that might appear once per frame. for these we want to check all messages we have in queue and supress it if so extern int HUD_toolong; extern void HUD_clear_messages(); extern void HUD_render_message_frame(); int HUD_init_message(int class_flag, const char * format, ... ); int HUD_init_message_va(int class_flag, const char * format, va_list args); int HUD_init_message_literal(int class_flag, const char *str); #endif dxx-rebirth-0.58.1-d1x/main/inferno.c000066400000000000000000000326071217717257200173120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * inferno.c: Entry point of program (main procedure) * * After main initializes everything, most of the time is spent in the loop * while (window_get_front()) * In this loop, the main menu is brought up first. * * main() for Inferno * */ char copyright[] = "DESCENT COPYRIGHT (C) 1994,1995 PARALLAX SOFTWARE CORPORATION"; #include #include #include #include #include #ifdef __unix__ #include #include #include #endif #include "pstypes.h" #include "strutil.h" #include "console.h" #include "gr.h" #include "key.h" #include "3d.h" #include "bm.h" #include "inferno.h" #include "dxxerror.h" #include "game.h" #include "segment.h" //for Side_to_verts #include "u_mem.h" #include "screens.h" #include "texmerge.h" #include "menu.h" #include "digi.h" #include "palette.h" #include "args.h" #include "titles.h" #include "text.h" #include "gauges.h" #include "gamefont.h" #include "kconfig.h" #include "newmenu.h" #include "config.h" #include "multi.h" #include "songs.h" #include "gameseq.h" #include "playsave.h" #include "collide.h" #include "newdemo.h" #include "joy.h" #include "../texmap/scanline.h" //for select_tmap -MM #include "event.h" #include "rbaudio.h" #ifndef __LINUX__ #include "messagebox.h" #endif #ifdef EDITOR #include "editor/editor.h" #include "editor/kdefs.h" #include "ui.h" #endif #include "vers_id.h" #ifdef USE_UDP #include "net_udp.h" #endif int Screen_mode=-1; //game screen or editor screen? int descent_critical_error = 0; unsigned int descent_critical_deverror = 0; unsigned int descent_critical_errcode = 0; int HiresGFXAvailable = 0; int MacHog = 0; // using a Mac hogfile? extern void arch_init(void); //read help from a file & print to screen void print_commandline_help() { printf( "\n System Options:\n\n"); printf( " -nonicefps Don't free CPU-cycles\n"); printf( " -maxfps Set maximum framerate to \n\t\t\t\t(default: %i, availble: 1-%i)\n", MAXIMUM_FPS, MAXIMUM_FPS); printf( " -hogdir set shared data directory to \n"); printf( " -nohogdir don't try to use shared data directory\n"); printf( " -use_players_dir put player files and saved games in Players subdirectory\n"); printf( " -lowmem Lowers animation detail for better performance with\n\t\t\t\tlow memory\n"); printf( " -pilot Select pilot automatically\n"); printf( " -autodemo Start in demo mode\n"); printf( " -window Run the game in a window\n"); printf( " -noborders Do not show borders in window mode\n"); printf( " -notitles Skip title screens\n"); printf( "\n Controls:\n\n"); printf( " -nocursor Hide mouse cursor\n"); printf( " -nomouse Deactivate mouse\n"); printf( " -nojoystick Deactivate joystick\n"); printf( " -nostickykeys Make CapsLock and NumLock non-sticky\n"); printf( "\n Sound:\n\n"); printf( " -nosound Disables sound output\n"); printf( " -nomusic Disables music output\n"); #ifdef USE_SDLMIXER printf( " -nosdlmixer Disable Sound output via SDL_mixer\n"); #endif // USE SDLMIXER printf( "\n Graphics:\n\n"); printf( " -lowresfont Force to use LowRes fonts\n"); #ifdef OGL printf( " -gl_fixedfont Do not scale fonts to current resolution\n"); #endif // OGL #if defined(USE_UDP) printf( "\n Multiplayer:\n\n"); printf( " -udp_hostaddr Use IP address/Hostname for manual game joining\n\t\t\t\t(default: %s)\n", UDP_MANUAL_ADDR_DEFAULT); printf( " -udp_hostport Use UDP port for manual game joining (default: %i)\n", UDP_PORT_DEFAULT); printf( " -udp_myport Set my own UDP port to (default: %i)\n", UDP_PORT_DEFAULT); #ifdef USE_TRACKER printf( " -tracker_hostaddr Address of Tracker server to register/query games to/from\n\t\t\t\t(default: %s)\n", TRACKER_ADDR_DEFAULT); printf( " -tracker_hostport Port of Tracker server to register/query games to/from\n\t\t\t\t(default: %i)\n", TRACKER_PORT_DEFAULT); #endif // USE_TRACKER #endif // defined(USE_UDP) #ifdef EDITOR printf( "\n Editor:\n\n"); printf( " -nobm Don't load BITMAPS.TBL and BITMAPS.BIN - use internal data\n"); #endif // EDITOR printf( "\n Debug (use only if you know what you're doing):\n\n"); printf( " -debug Enable debugging output.\n"); printf( " -verbose Enable verbose output.\n"); printf( " -safelog Write gamelog.txt unbuffered.\n\t\t\t\tUse to keep helpful output to trace program crashes.\n"); printf( " -norun Bail out after initialization\n"); printf( " -renderstats Enable renderstats info by default\n"); printf( " -text Specify alternate .tex file\n"); printf( " -tmap Select texmapper to use\n\t\t\t\t(default: c, available: c, fp, quad, i386)\n"); printf( " -showmeminfo Show memory statistics\n"); printf( " -nodoublebuffer Disable Doublebuffering\n"); printf( " -bigpig Use uncompressed RLE bitmaps\n"); printf( " -16bpp Use 16Bpp instead of 32Bpp\n"); #ifdef OGL printf( " -gl_oldtexmerge Use old texmerge, uses more ram, but might be faster\n"); printf( " -gl_intensity4_ok Override DbgGlIntensity4Ok (default: 1)\n"); printf( " -gl_luminance4_alpha4_ok Override DbgGlLuminance4Alpha4Ok (default: 1)\n"); printf( " -gl_rgba2_ok Override DbgGlRGBA2Ok (default: 1)\n"); printf( " -gl_readpixels_ok Override DbgGlReadPixelsOk (default: 1)\n"); printf( " -gl_gettexlevelparam_ok Override DbgGlGetTexLevelParamOk (default: 1)\n"); #else printf( " -hwsurface Use SDL HW Surface\n"); printf( " -asyncblit Use queued blits over SDL. Can speed up rendering\n"); #endif // OGL printf( "\n Help:\n\n"); printf( " -help, -h, -?, ? View this help screen\n"); printf( "\n\n"); } int Quitting = 0; // Default event handler for everything except the editor int standard_handler(d_event *event) { int key; if (Quitting) { window *wind = window_get_front(); if (!wind) return 0; if (wind == Game_wind) { int choice; Quitting = 0; choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME ); if (choice != 0) return 0; else { GameArg.SysAutoDemo = 0; Quitting = 1; } } // Close front window, let the code flow continue until all windows closed or quit cancelled if (!window_close(wind)) Quitting = 0; return 1; } switch (event->type) { case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: // No window selecting // We stay with the current one until it's closed/hidden or another one is made // Not the case for the editor break; case EVENT_KEY_COMMAND: key = event_key_get(event); switch (key) { #ifdef macintosh case KEY_COMMAND + KEY_SHIFTED + KEY_3: #endif case KEY_PRINT_SCREEN: { gr_set_current_canvas(NULL); save_screen_shot(0); return 1; } case KEY_ALTED+KEY_ENTER: case KEY_ALTED+KEY_PADENTER: if (Game_wind) if (Game_wind == window_get_front()) return 0; gr_toggle_fullscreen(); return 1; #ifndef NDEBUG case KEY_BACKSP: Int3(); return 1; #endif #if defined(__APPLE__) || defined(macintosh) case KEY_COMMAND+KEY_Q: // Alt-F4 already taken, too bad Quitting = 1; return 1; #endif case KEY_SHIFTED + KEY_ESC: con_showup(); return 1; } break; case EVENT_WINDOW_DRAW: case EVENT_IDLE: //see if redbook song needs to be restarted RBACheckFinishedHook(); return 1; case EVENT_QUIT: #ifdef EDITOR if (SafetyCheck()) #endif Quitting = 1; return 1; default: break; } return 0; } jmp_buf LeaveEvents; #define PROGNAME argv[0] // DESCENT by Parallax Software // Descent Main int main(int argc, char *argv[]) { mem_init(); #ifdef __LINUX__ error_init(NULL); #else error_init(msgbox_error); set_warn_func(msgbox_warning); #endif PHYSFSX_init(argc, argv); con_init(); // Initialise the console setbuf(stdout, NULL); // unbuffered output via printf #ifdef _WIN32 freopen( "CON", "w", stdout ); freopen( "CON", "w", stderr ); #endif if (GameArg.SysShowCmdHelp) { print_commandline_help(); return(0); } printf("\nType %s -help' for a list of command-line options.\n\n", PROGNAME); PHYSFSX_listSearchPathContent(); if (!PHYSFSX_checkSupportedArchiveTypes()) return(0); if (! PHYSFSX_contfile_init("descent.hog", 1)) #define DXX_NAME_NUMBER "1" #define DXX_HOGFILE_NAMES "descent.hog" #if defined(__unix__) && !defined(__APPLE__) #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\t$HOME/.d" DXX_NAME_NUMBER "x-rebirth\n" \ "\t" SHAREPATH "\n" #else #define DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tDirectory containing D" DXX_NAME_NUMBER "X\n" #endif #if (defined(__APPLE__) && defined(__MACH__)) || defined(macintosh) #define DXX_HOGFILE_APPLICATION_BUNDLE \ "\tIn 'Resources' inside the application bundle\n" #else #define DXX_HOGFILE_APPLICATION_BUNDLE "" #endif #define DXX_MISSING_HOGFILE_ERROR_TEXT \ "Could not find a valid hog file (" DXX_HOGFILE_NAMES ")\nPossible locations are:\n" \ DXX_HOGFILE_PROGRAM_DATA_DIRECTORY \ "\tIn a subdirectory called 'Data'\n" \ DXX_HOGFILE_APPLICATION_BUNDLE \ "Or use the -hogdir option to specify an alternate location." Error(DXX_MISSING_HOGFILE_ERROR_TEXT); switch (PHYSFSX_fsize("descent.hog")) { case D1_MAC_SHARE_MISSION_HOGSIZE: case D1_MAC_MISSION_HOGSIZE: MacHog = 1; // used for fonts and the Automap break; } load_text(); //print out the banner title con_printf(CON_NORMAL, "%s %s\n", DESCENT_VERSION, g_descent_build_datetime); // D1X version con_printf(CON_NORMAL, "This is a MODIFIED version of Descent, based on %s.\n", BASED_VERSION); con_printf(CON_NORMAL, "%s\n%s\n",TXT_COPYRIGHT,TXT_TRADEMARK); con_printf(CON_NORMAL, "Copyright (C) 2005-2011 Christian Beckhaeuser\n\n"); if (GameArg.DbgVerbose) con_printf(CON_VERBOSE,"%s%s", TXT_VERBOSE_1, "\n"); ReadConfigFile(); PHYSFSX_addArchiveContent(); arch_init(); select_tmap(GameArg.DbgTexMap); con_printf(CON_VERBOSE, "Going into graphics mode...\n"); gr_set_mode(Game_screen_mode); // Load the palette stuff. Returns non-zero if error. con_printf(CON_DEBUG, "Initializing palette system...\n" ); gr_use_palette_table( "PALETTE.256" ); con_printf(CON_DEBUG, "Initializing font system...\n" ); gamefont_init(); // must load after palette data loaded. set_default_handler(standard_handler); show_titles(); set_screen_mode(SCREEN_MENU); con_printf( CON_DEBUG, "\nDoing gamedata_init..." ); gamedata_init(); if (GameArg.DbgNoRun) return(0); con_printf( CON_DEBUG, "\nInitializing texture caching system..." ); texmerge_init( 10 ); // 10 cache bitmaps con_printf( CON_DEBUG, "\nRunning game...\n" ); init_game(); Players[Player_num].callsign[0] = '\0'; key_flush(); if(GameArg.SysPilot) { char filename[32] = ""; int j; if (GameArg.SysUsePlayersDir) strcpy(filename, "Players/"); strncat(filename, GameArg.SysPilot, 12); filename[8 + 12] = '\0'; // unfortunately strncat doesn't put the terminating 0 on the end if it reaches 'n' for (j = GameArg.SysUsePlayersDir? 8 : 0; filename[j] != '\0'; j++) { switch (filename[j]) { case ' ': filename[j] = '\0'; } } if(!strstr(filename,".plr")) // if player hasn't specified .plr extension in argument, add it strcat(filename,".plr"); if(PHYSFSX_exists(filename,0)) { strcpy(strstr(filename,".plr"),"\0"); strcpy(Players[Player_num].callsign, GameArg.SysUsePlayersDir? &filename[8] : filename); read_player_file(); WriteConfigFile(); } } Game_mode = GM_GAME_OVER; DoMenu(); setjmp(LeaveEvents); while (window_get_front()) // Send events to windows and the default handler event_process(); // Tidy up - avoids a crash on exit { window *wind; show_menus(); while ((wind = window_get_front())) window_close(wind); } WriteConfigFile(); show_order_form(); con_printf( CON_DEBUG, "\nCleanup...\n" ); close_game(); texmerge_close(); gamedata_close(); gamefont_close(); free_text(); args_exit(); newmenu_free_background(); free_mission(); PHYSFSX_removeArchiveContent(); return(0); //presumably successful exit } dxx-rebirth-0.58.1-d1x/main/inferno.h000066400000000000000000000031231217717257200173060ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header file for Inferno. Should be included in all source files. * */ #ifndef _INFERNO_H #define _INFERNO_H #include struct d_event; #if defined(__APPLE__) || defined(macintosh) #define KEY_MAC(x) x #else // do not use MAC, it will break MSVC compilation somewhere in rpcdce.h #define KEY_MAC(x) #endif /** ** Constants **/ // How close two points must be in all dimensions to be considered the same point. #define FIX_EPSILON 10 // the maximum length of a filename #define FILENAME_LEN 13 // a filename, useful for declaring arrays of filenames typedef char d_fname[FILENAME_LEN]; /** ** Global variables **/ extern jmp_buf LeaveEvents; extern int Quitting; extern int Screen_mode; // editor screen or game screen? extern int MacHog; // Default event handler for everything except the editor int standard_handler(struct d_event *event); #endif dxx-rebirth-0.58.1-d1x/main/kconfig.c000066400000000000000000002060111217717257200172620ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to configure keyboard, joystick, etc.. * */ #include #include #include #include #include #include "dxxerror.h" #include "pstypes.h" #include "gr.h" #include "window.h" #include "console.h" #include "palette.h" #include "game.h" #include "gamefont.h" #include "iff.h" #include "u_mem.h" #include "kconfig.h" #include "gauges.h" #include "rbaudio.h" #include "render.h" #include "digi.h" #include "newmenu.h" #include "endlevel.h" #include "multi.h" #include "timer.h" #include "text.h" #include "player.h" #include "menu.h" #include "automap.h" #include "args.h" #include "lighting.h" #include "ai.h" #include "cntrlcen.h" #include "collide.h" #include "playsave.h" #ifdef OGL #include "ogl_init.h" #endif #define TABLE_CREATION 1 // Array used to 'blink' the cursor while waiting for a keypress. static const sbyte fades[64] = { 1,1,1,2,2,3,4,4,5,6,8,9,10,12,13,15,16,17,19,20,22,23,24,26,27,28,28,29,30,30,31,31,31,31,31,30,30,29,28,28,27,26,24,23,22,20,19,17,16,15,13,12,10,9,8,6,5,4,4,3,2,2,1,1 }; static const char invert_text[2][2] = { "N", "Y" }; char *joybutton_text[JOY_MAX_BUTTONS]; char *joyaxis_text[JOY_MAX_AXES]; static const char mouseaxis_text[][8] = { "L/R", "F/B", "WHEEL" }; static const char mousebutton_text[][8] = { "LEFT", "RIGHT", "MID", "M4", "M5", "M6", "M7", "M8", "M9", "M10","M11","M12","M13","M14","M15","M16" }; static const ubyte system_keys[19] = { KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_MINUS, KEY_EQUAL, KEY_PRINT_SCREEN, KEY_CAPSLOCK, KEY_SCROLLOCK, KEY_NUMLOCK }; // KEY_*LOCK should always be last since we wanna skip these if -nostickykeys control_info Controls; fix Cruise_speed=0; #define BT_KEY 0 #define BT_MOUSE_BUTTON 1 #define BT_MOUSE_AXIS 2 #define BT_JOY_BUTTON 3 #define BT_JOY_AXIS 4 #define BT_INVERT 5 #define STATE_BIT1 1 #define STATE_BIT2 2 #define STATE_BIT3 4 #define STATE_BIT4 8 #define STATE_BIT5 16 #define INFO_Y (188) typedef struct kc_item { const short id; // The id of this item const short x, y; // x, y pos of label const short w1; // x pos of input field const short w2; // length of input field #ifndef TABLE_CREATION const #endif short u,d,l,r; // neighboring field ids for cursor navigation //short text_num1; const char *const text; const ubyte type; ubyte value; // what key,button,etc ubyte *const ci_state_ptr; const int state_bit; ubyte *const ci_count_ptr; } kc_item; typedef struct kc_menu { window *wind; kc_item *items; const char *title; int nitems; int citem; int old_jaxis[JOY_MAX_AXES]; int old_maxis[3]; ubyte changing; ubyte q_fade_i; // for flashing the question mark ubyte mouse_state; } kc_menu; const ubyte DefaultKeySettings[3][MAX_CONTROLS] = { {0xc8,0x48,0xd0,0x50,0xcb,0x4b,0xcd,0x4d,0x38,0xff,0xff,0x4f,0xff,0x51,0xff,0x4a,0xff,0x4e,0xff,0xff,0x10,0x47,0x12,0x49,0x1d,0x9d,0x39,0xff,0x21,0xff,0x1e,0xff,0x2c,0xff,0x30,0xff,0x13,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0x33,0x0,0x34,0x0}, {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0}, {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}, }; const ubyte DefaultKeySettingsD1X[MAX_D1X_CONTROLS] = { 0x2,0xff,0xff,0x3,0xff,0xff,0x4,0xff,0xff,0x5,0xff,0xff,0x6,0xff,0xff,0x7,0xff,0xff,0x8,0xff,0xff,0x9,0xff,0xff,0xa,0xff,0xff,0xb,0xff,0xff }; // id, x, y, w1, w2, u, d, l, r, text, type, value kc_item kc_keyboard[NUM_KEY_CONTROLS] = { { 0, 15, 49, 71, 26, 43, 2, 49, 1,"Pitch forward", BT_KEY, 255, &Controls.key_pitch_forward_state, STATE_BIT1, NULL }, { 1, 15, 49,100, 26, 48, 3, 0, 24,"Pitch forward", BT_KEY, 255, &Controls.key_pitch_forward_state, STATE_BIT2, NULL }, { 2, 15, 57, 71, 26, 0, 4, 25, 3,"Pitch backward", BT_KEY, 255, &Controls.key_pitch_backward_state, STATE_BIT1, NULL }, { 3, 15, 57,100, 26, 1, 5, 2, 26,"Pitch backward", BT_KEY, 255, &Controls.key_pitch_backward_state, STATE_BIT2, NULL }, { 4, 15, 65, 71, 26, 2, 6, 27, 5,"Turn left", BT_KEY, 255, &Controls.key_heading_left_state, STATE_BIT1, NULL }, { 5, 15, 65,100, 26, 3, 7, 4, 28,"Turn left", BT_KEY, 255, &Controls.key_heading_left_state, STATE_BIT2, NULL }, { 6, 15, 73, 71, 26, 4, 8, 29, 7,"Turn right", BT_KEY, 255, &Controls.key_heading_right_state, STATE_BIT1, NULL }, { 7, 15, 73,100, 26, 5, 9, 6, 34,"Turn right", BT_KEY, 255, &Controls.key_heading_right_state, STATE_BIT2, NULL }, { 8, 15, 85, 71, 26, 6, 10, 35, 9,"Slide on", BT_KEY, 255, &Controls.slide_on_state, STATE_BIT1, NULL }, { 9, 15, 85,100, 26, 7, 11, 8, 36,"Slide on", BT_KEY, 255, &Controls.slide_on_state, STATE_BIT2, NULL }, { 10, 15, 93, 71, 26, 8, 12, 37, 11,"Slide left", BT_KEY, 255, &Controls.key_slide_left_state, STATE_BIT1, NULL }, { 11, 15, 93,100, 26, 9, 13, 10, 44,"Slide left", BT_KEY, 255, &Controls.key_slide_left_state, STATE_BIT2, NULL }, { 12, 15,101, 71, 26, 10, 14, 45, 13,"Slide right", BT_KEY, 255, &Controls.key_slide_right_state, STATE_BIT1, NULL }, { 13, 15,101,100, 26, 11, 15, 12, 30,"Slide right", BT_KEY, 255, &Controls.key_slide_right_state, STATE_BIT2, NULL }, { 14, 15,109, 71, 26, 12, 16, 31, 15,"Slide up", BT_KEY, 255, &Controls.key_slide_up_state, STATE_BIT1, NULL }, { 15, 15,109,100, 26, 13, 17, 14, 32,"Slide up", BT_KEY, 255, &Controls.key_slide_up_state, STATE_BIT2, NULL }, { 16, 15,117, 71, 26, 14, 18, 33, 17,"Slide down", BT_KEY, 255, &Controls.key_slide_down_state, STATE_BIT1, NULL }, { 17, 15,117,100, 26, 15, 19, 16, 38,"Slide down", BT_KEY, 255, &Controls.key_slide_down_state, STATE_BIT2, NULL }, { 18, 15,129, 71, 26, 16, 20, 39, 19,"Bank on", BT_KEY, 255, &Controls.bank_on_state, STATE_BIT1, NULL }, { 19, 15,129,100, 26, 17, 21, 18, 40,"Bank on", BT_KEY, 255, &Controls.bank_on_state, STATE_BIT2, NULL }, { 20, 15,137, 71, 26, 18, 22, 41, 21,"Bank left", BT_KEY, 255, &Controls.key_bank_left_state, STATE_BIT1, NULL }, { 21, 15,137,100, 26, 19, 23, 20, 42,"Bank left", BT_KEY, 255, &Controls.key_bank_left_state, STATE_BIT2, NULL }, { 22, 15,145, 71, 26, 20, 46, 43, 23,"Bank right", BT_KEY, 255, &Controls.key_bank_right_state, STATE_BIT1, NULL }, { 23, 15,145,100, 26, 21, 47, 22, 46,"Bank right", BT_KEY, 255, &Controls.key_bank_right_state, STATE_BIT2, NULL }, { 24,158, 49, 83, 26, 49, 26, 1, 25,"Fire primary", BT_KEY, 255, &Controls.fire_primary_state, STATE_BIT1, &Controls.fire_primary_count }, { 25,158, 49,112, 26, 42, 27, 24, 2,"Fire primary", BT_KEY, 255, &Controls.fire_primary_state, STATE_BIT2, &Controls.fire_primary_count }, { 26,158, 57, 83, 26, 24, 28, 3, 27,"Fire secondary", BT_KEY, 255, &Controls.fire_secondary_state, STATE_BIT1, &Controls.fire_secondary_count }, { 27,158, 57,112, 26, 25, 29, 26, 4,"Fire secondary", BT_KEY, 255, &Controls.fire_secondary_state, STATE_BIT2, &Controls.fire_secondary_count }, { 28,158, 65, 83, 26, 26, 34, 5, 29,"Fire flare", BT_KEY, 255, NULL, 0, &Controls.fire_flare_count }, { 29,158, 65,112, 26, 27, 35, 28, 6,"Fire flare", BT_KEY, 255, NULL, 0, &Controls.fire_flare_count }, { 30,158,105, 83, 26, 44, 32, 13, 31,"Accelerate", BT_KEY, 255, &Controls.accelerate_state, STATE_BIT1, NULL }, { 31,158,105,112, 26, 45, 33, 30, 14,"Accelerate", BT_KEY, 255, &Controls.accelerate_state, STATE_BIT2, NULL }, { 32,158,113, 83, 26, 30, 38, 15, 33,"Reverse", BT_KEY, 255, &Controls.reverse_state, STATE_BIT1, NULL }, { 33,158,113,112, 26, 31, 39, 32, 16,"Reverse", BT_KEY, 255, &Controls.reverse_state, STATE_BIT2, NULL }, { 34,158, 73, 83, 26, 28, 36, 7, 35,"Drop bomb", BT_KEY, 255, NULL, 0, &Controls.drop_bomb_count }, { 35,158, 73,112, 26, 29, 37, 34, 8,"Drop bomb", BT_KEY, 255, NULL, 0, &Controls.drop_bomb_count }, { 36,158, 85, 83, 26, 34, 44, 9, 37,"Rear view", BT_KEY, 255, &Controls.rear_view_state, STATE_BIT1, &Controls.rear_view_count }, { 37,158, 85,112, 26, 35, 45, 36, 10,"Rear view", BT_KEY, 255, &Controls.rear_view_state, STATE_BIT2, &Controls.rear_view_count }, { 38,158,125, 83, 26, 32, 40, 17, 39,"Cruise faster", BT_KEY, 255, &Controls.cruise_plus_state, STATE_BIT1, NULL }, { 39,158,125,112, 26, 33, 41, 38, 18,"Cruise faster", BT_KEY, 255, &Controls.cruise_plus_state, STATE_BIT2, NULL }, { 40,158,133, 83, 26, 38, 42, 19, 41,"Cruise slower", BT_KEY, 255, &Controls.cruise_minus_state, STATE_BIT1, NULL }, { 41,158,133,112, 26, 39, 43, 40, 20,"Cruise slower", BT_KEY, 255, &Controls.cruise_minus_state, STATE_BIT2, NULL }, { 42,158,141, 83, 26, 40, 25, 21, 43,"Cruise off", BT_KEY, 255, NULL, 0, &Controls.cruise_off_count }, { 43,158,141,112, 26, 41, 0, 42, 22,"Cruise off", BT_KEY, 255, NULL, 0, &Controls.cruise_off_count }, { 44,158, 93, 83, 26, 36, 30, 11, 45,"Automap", BT_KEY, 255, &Controls.automap_state, STATE_BIT1, &Controls.automap_count }, { 45,158, 93,112, 26, 37, 31, 44, 12,"Automap", BT_KEY, 255, &Controls.automap_state, STATE_BIT2, &Controls.automap_count }, { 46, 15,157, 71, 26, 22, 48, 23, 47,"Cycle Primary", BT_KEY, 255, NULL, 0, &Controls.cycle_primary_count }, { 47, 15,157,100, 26, 23, 49, 46, 48,"Cycle Primary", BT_KEY, 255, NULL, 0, &Controls.cycle_primary_count }, { 48, 15,165, 71, 26, 46, 1, 47, 49,"Cycle Second.", BT_KEY, 255, NULL, 0, &Controls.cycle_secondary_count }, { 49, 15,165,100, 26, 47, 24, 48, 0,"Cycle Second.", BT_KEY, 255, NULL, 0, &Controls.cycle_secondary_count }, }; kc_item kc_joystick[NUM_JOYSTICK_CONTROLS] = { { 0, 22, 46, 82, 26, 15, 1, 24, 29,"Fire primary", BT_JOY_BUTTON, 255, &Controls.fire_primary_state, STATE_BIT3, &Controls.fire_primary_count }, { 1, 22, 54, 82, 26, 0, 4, 34, 30,"Fire secondary", BT_JOY_BUTTON, 255, &Controls.fire_secondary_state, STATE_BIT3, &Controls.fire_secondary_count }, { 2, 22, 78, 82, 26, 26, 3, 37, 31,"Accelerate", BT_JOY_BUTTON, 255, &Controls.accelerate_state, STATE_BIT3, NULL }, { 3, 22, 86, 82, 26, 2, 25, 38, 32,"Reverse", BT_JOY_BUTTON, 255, &Controls.reverse_state, STATE_BIT3, NULL }, { 4, 22, 62, 82, 26, 1, 26, 35, 33,"Fire flare", BT_JOY_BUTTON, 255, NULL, 0, &Controls.fire_flare_count }, { 5,174, 46, 74, 26, 23, 6, 29, 34,"Slide on", BT_JOY_BUTTON, 255, &Controls.slide_on_state, STATE_BIT3, NULL }, { 6,174, 54, 74, 26, 5, 7, 30, 35,"Slide left", BT_JOY_BUTTON, 255, &Controls.btn_slide_left_state, STATE_BIT3, NULL }, { 7,174, 62, 74, 26, 6, 8, 33, 36,"Slide right", BT_JOY_BUTTON, 255, &Controls.btn_slide_right_state, STATE_BIT3, NULL }, { 8,174, 70, 74, 26, 7, 9, 43, 37,"Slide up", BT_JOY_BUTTON, 255, &Controls.btn_slide_up_state, STATE_BIT3, NULL }, { 9,174, 78, 74, 26, 8, 10, 31, 38,"Slide down", BT_JOY_BUTTON, 255, &Controls.btn_slide_down_state, STATE_BIT3, NULL }, { 10,174, 86, 74, 26, 9, 11, 32, 39,"Bank on", BT_JOY_BUTTON, 255, &Controls.bank_on_state, STATE_BIT3, NULL }, { 11,174, 94, 74, 26, 10, 12, 42, 40,"Bank left", BT_JOY_BUTTON, 255, &Controls.btn_bank_left_state, STATE_BIT3, NULL }, { 12,174,102, 74, 26, 11, 44, 28, 41,"Bank right", BT_JOY_BUTTON, 255, &Controls.btn_bank_right_state, STATE_BIT3, NULL }, { 13, 22,154, 51, 26, 47, 15, 47, 14,"Pitch U/D", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 14, 22,154, 99, 8, 27, 16, 13, 17,"Pitch U/D", BT_INVERT, 255, NULL, 0, NULL }, { 15, 22,162, 51, 26, 13, 0, 18, 16,"Turn L/R", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 16, 22,162, 99, 8, 14, 29, 15, 19,"Turn L/R", BT_INVERT, 255, NULL, 0, NULL }, { 17,164,154, 58, 26, 28, 19, 14, 18,"Slide L/R", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 18,164,154,106, 8, 45, 20, 17, 15,"Slide L/R", BT_INVERT, 255, NULL, 0, NULL }, { 19,164,162, 58, 26, 17, 21, 16, 20,"Slide U/D", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 20,164,162,106, 8, 18, 22, 19, 21,"Slide U/D", BT_INVERT, 255, NULL, 0, NULL }, { 21,164,170, 58, 26, 19, 23, 20, 22,"Bank L/R", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 22,164,170,106, 8, 20, 24, 21, 23,"Bank L/R", BT_INVERT, 255, NULL, 0, NULL }, { 23,164,178, 58, 26, 21, 5, 22, 24,"Throttle", BT_JOY_AXIS, 255, NULL, 0, NULL }, { 24,164,178,106, 8, 22, 34, 23, 0,"Throttle", BT_INVERT, 255, NULL, 0, NULL }, { 25, 22, 94, 82, 26, 3, 27, 39, 42,"Rear view", BT_JOY_BUTTON, 255, &Controls.rear_view_state, STATE_BIT3, &Controls.rear_view_count }, { 26, 22, 70, 82, 26, 4, 2, 36, 43,"Drop bomb", BT_JOY_BUTTON, 255, NULL, 0, &Controls.drop_bomb_count }, { 27, 22,102, 82, 26, 25, 14, 40, 28,"Automap", BT_JOY_BUTTON, 255, &Controls.automap_state, STATE_BIT3, &Controls.automap_count }, { 28, 22,102,111, 26, 42, 17, 27, 12,"Automap", BT_JOY_BUTTON, 255, &Controls.automap_state, STATE_BIT4, &Controls.automap_count }, { 29, 22, 46,111, 26, 16, 30, 0, 5,"Fire primary", BT_JOY_BUTTON, 255, &Controls.fire_primary_state, STATE_BIT4, &Controls.fire_primary_count }, { 30, 22, 54,111, 26, 29, 33, 1, 6,"Fire secondary", BT_JOY_BUTTON, 255, &Controls.fire_secondary_state, STATE_BIT4, &Controls.fire_secondary_count }, { 31, 22, 78,111, 26, 43, 32, 2, 9,"Accelerate", BT_JOY_BUTTON, 255, &Controls.accelerate_state, STATE_BIT4, NULL }, { 32, 22, 86,111, 26, 31, 42, 3, 10,"Reverse", BT_JOY_BUTTON, 255, &Controls.reverse_state, STATE_BIT4, NULL }, { 33, 22, 62,111, 26, 30, 43, 4, 7,"Fire flare", BT_JOY_BUTTON, 255, NULL, 0, &Controls.fire_flare_count }, { 34,174, 46,104, 26, 24, 35, 5, 1,"Slide on", BT_JOY_BUTTON, 255, &Controls.slide_on_state, STATE_BIT4, NULL }, { 35,174, 54,104, 26, 34, 36, 6, 4,"Slide left", BT_JOY_BUTTON, 255, &Controls.btn_slide_left_state, STATE_BIT4, NULL }, { 36,174, 62,104, 26, 35, 37, 7, 26,"Slide right", BT_JOY_BUTTON, 255, &Controls.btn_slide_right_state, STATE_BIT4, NULL }, { 37,174, 70,104, 26, 36, 38, 8, 2,"Slide up", BT_JOY_BUTTON, 255, &Controls.btn_slide_up_state, STATE_BIT4, NULL }, { 38,174, 78,104, 26, 37, 39, 9, 3,"Slide down", BT_JOY_BUTTON, 255, &Controls.btn_slide_down_state, STATE_BIT4, NULL }, { 39,174, 86,104, 26, 38, 40, 10, 25,"Bank on", BT_JOY_BUTTON, 255, &Controls.bank_on_state, STATE_BIT4, NULL }, { 40,174, 94,104, 26, 39, 41, 11, 27,"Bank left", BT_JOY_BUTTON, 255, &Controls.btn_bank_left_state, STATE_BIT4, NULL }, { 41,174,102,104, 26, 40, 46, 12, 44,"Bank right", BT_JOY_BUTTON, 255, &Controls.btn_bank_right_state, STATE_BIT4, NULL }, { 42, 22, 94,111, 26, 32, 28, 25, 11,"Rear view", BT_JOY_BUTTON, 255, &Controls.rear_view_state, STATE_BIT4, &Controls.rear_view_count }, { 43, 22, 70,111, 26, 33, 31, 26, 8,"Drop bomb", BT_JOY_BUTTON, 255, NULL, 0, &Controls.drop_bomb_count }, { 44,174,110, 74, 26, 12, 45, 41, 46,"Cycle Primary", BT_JOY_BUTTON, 255, NULL, 0, &Controls.cycle_primary_count }, { 45,174,118, 74, 26, 44, 18, 46, 47,"Cycle Secondary", BT_JOY_BUTTON, 255, NULL, 0, &Controls.cycle_secondary_count }, { 46,174,110,104, 26, 41, 47, 44, 45,"Cycle Primary", BT_JOY_BUTTON, 255, NULL, 0, &Controls.cycle_primary_count }, { 47,174,118,104, 26, 46, 13, 45, 13,"Cycle Secondary", BT_JOY_BUTTON, 255, NULL, 0, &Controls.cycle_secondary_count }, }; kc_item kc_mouse[NUM_MOUSE_CONTROLS] = { { 0, 25, 46, 85, 26, 19, 1, 20, 5,"Fire primary", BT_MOUSE_BUTTON, 255, &Controls.fire_primary_state, STATE_BIT5, &Controls.fire_primary_count }, { 1, 25, 54, 85, 26, 0, 4, 5, 6,"Fire secondary", BT_MOUSE_BUTTON, 255, &Controls.fire_secondary_state, STATE_BIT5, &Controls.fire_secondary_count }, { 2, 25, 78, 85, 26, 26, 3, 8, 9,"Accelerate", BT_MOUSE_BUTTON, 255, &Controls.accelerate_state, STATE_BIT5, NULL }, { 3, 25, 86, 85, 26, 2, 25, 9, 10,"Reverse", BT_MOUSE_BUTTON, 255, &Controls.reverse_state, STATE_BIT5, NULL }, { 4, 25, 62, 85, 26, 1, 26, 6, 7,"Fire flare", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.fire_flare_count }, { 5,180, 46, 59, 26, 23, 6, 0, 1,"Slide on", BT_MOUSE_BUTTON, 255, &Controls.slide_on_state, STATE_BIT5, NULL }, { 6,180, 54, 59, 26, 5, 7, 1, 4,"Slide left", BT_MOUSE_BUTTON, 255, &Controls.btn_slide_left_state, STATE_BIT5, NULL }, { 7,180, 62, 59, 26, 6, 8, 4, 26,"Slide right", BT_MOUSE_BUTTON, 255, &Controls.btn_slide_right_state, STATE_BIT5, NULL }, { 8,180, 70, 59, 26, 7, 9, 26, 2,"Slide up", BT_MOUSE_BUTTON, 255, &Controls.btn_slide_up_state, STATE_BIT5, NULL }, { 9,180, 78, 59, 26, 8, 10, 2, 3,"Slide down", BT_MOUSE_BUTTON, 255, &Controls.btn_slide_down_state, STATE_BIT5, NULL }, { 10,180, 86, 59, 26, 9, 11, 3, 25,"Bank on", BT_MOUSE_BUTTON, 255, &Controls.bank_on_state, STATE_BIT5, NULL }, { 11,180, 94, 59, 26, 10, 12, 25, 27,"Bank left", BT_MOUSE_BUTTON, 255, &Controls.btn_bank_left_state, STATE_BIT5, NULL }, { 12,180,102, 59, 26, 11, 22, 27, 28,"Bank right", BT_MOUSE_BUTTON, 255, &Controls.btn_bank_right_state, STATE_BIT5, NULL }, { 13, 25,154, 58, 26, 24, 15, 28, 14,"Pitch U/D", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 14, 25,154,106, 8, 28, 16, 13, 21,"Pitch U/D", BT_INVERT, 255, NULL, 0, NULL }, { 15, 25,162, 58, 26, 13, 17, 22, 16,"Turn L/R", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 16, 25,162,106, 8, 14, 18, 15, 23,"Turn L/R", BT_INVERT, 255, NULL, 0, NULL }, { 17, 25,170, 58, 26, 15, 19, 24, 18,"Slide L/R", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 18, 25,170,106, 8, 16, 20, 17, 19,"Slide L/R", BT_INVERT, 255, NULL, 0, NULL }, { 19, 25,178, 58, 26, 17, 0, 18, 20,"Slide U/D", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 20, 25,178,106, 8, 18, 21, 19, 0,"Slide U/D", BT_INVERT, 255, NULL, 0, NULL }, { 21,180,154, 58, 26, 20, 23, 14, 22,"Bank L/R", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 22,180,154,106, 8, 12, 24, 21, 15,"Bank L/R", BT_INVERT, 255, NULL, 0, NULL }, { 23,180,162, 58, 26, 21, 5, 16, 24,"Throttle", BT_MOUSE_AXIS, 255, NULL, 0, NULL }, { 24,180,162,106, 8, 22, 13, 23, 17,"Throttle", BT_INVERT, 255, NULL, 0, NULL }, { 25, 25, 94, 85, 26, 3, 27, 10, 11,"Rear view", BT_MOUSE_BUTTON, 255, &Controls.rear_view_state, STATE_BIT5, &Controls.rear_view_count }, { 26, 25, 70, 85, 26, 4, 2, 7, 8,"Drop bomb", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.drop_bomb_count }, { 27, 25,102, 85, 26, 25, 28, 11, 12,"Cycle Primary", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.cycle_primary_count }, { 28, 25,110, 85, 26, 27, 14, 12, 13,"Cycle Secondary", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.cycle_secondary_count }, }; kc_item kc_d1x[NUM_D1X_CONTROLS] = { { 0, 15, 69,142, 26, 29, 3, 29, 1,"LASER CANNON", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 1, 15, 69,200, 26, 27, 4, 0, 2,"LASER CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 2, 15, 69,258, 26, 28, 5, 1, 3,"LASER CANNON", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 3, 15, 77,142, 26, 0, 6, 2, 4,"VULCAN CANNON", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 4, 15, 77,200, 26, 1, 7, 3, 5,"VULCAN CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 5, 15, 77,258, 26, 2, 8, 4, 6,"VULCAN CANNON", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 6, 15, 85,142, 26, 3, 9, 5, 7,"SPREADFIRE CANNON", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 7, 15, 85,200, 26, 4, 10, 6, 8,"SPREADFIRE CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 8, 15, 85,258, 26, 5, 11, 7, 9,"SPREADFIRE CANNON", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 9, 15, 93,142, 26, 6, 12, 8, 10,"PLASMA CANNON", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 10, 15, 93,200, 26, 7, 13, 9, 11,"PLASMA CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 11, 15, 93,258, 26, 8, 14, 10, 12,"PLASMA CANNON", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 12, 15,101,142, 26, 9, 15, 11, 13,"FUSION CANNON", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 13, 15,101,200, 26, 10, 16, 12, 14,"FUSION CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 14, 15,101,258, 26, 11, 17, 13, 15,"FUSION CANNON", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 15, 15,109,142, 26, 12, 18, 14, 16,"CONCUSSION MISSILE", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 16, 15,109,200, 26, 13, 19, 15, 17,"CONCUSSION MISSILE", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 17, 15,109,258, 26, 14, 20, 16, 18,"CONCUSSION MISSILE", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 18, 15,117,142, 26, 15, 21, 17, 19,"HOMING MISSILE", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 19, 15,117,200, 26, 16, 22, 18, 20,"HOMING MISSILE", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 20, 15,117,258, 26, 17, 23, 19, 21,"HOMING MISSILE", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 21, 15,125,142, 26, 18, 24, 20, 22,"PROXIMITY BOMB", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 22, 15,125,200, 26, 19, 25, 21, 23,"PROXIMITY BOMB", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 23, 15,125,258, 26, 20, 26, 22, 24,"PROXIMITY BOMB", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 24, 15,133,142, 26, 21, 27, 23, 25,"SMART MISSILE", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 25, 15,133,200, 26, 22, 28, 24, 26,"SMART MISSILE", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 26, 15,133,258, 26, 23, 29, 25, 27,"SMART MISSILE", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 27, 15,141,142, 26, 24, 1, 26, 28,"MEGA MISSILE", BT_KEY, 255, NULL, 0, &Controls.select_weapon_count }, { 28, 15,141,200, 26, 25, 2, 27, 29,"MEGA MISSILE", BT_JOY_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, { 29, 15,141,258, 26, 26, 0, 28, 0,"MEGA MISSILE", BT_MOUSE_BUTTON, 255, NULL, 0, &Controls.select_weapon_count }, }; void kc_drawitem( kc_item *item, int is_current ); void kc_change_key( kc_menu *menu, d_event *event, kc_item * item ); void kc_change_joybutton( kc_menu *menu, d_event *event, kc_item * item ); void kc_change_mousebutton( kc_menu *menu, d_event *event, kc_item * item ); void kc_change_joyaxis( kc_menu *menu, d_event *event, kc_item * item ); void kc_change_mouseaxis( kc_menu *menu, d_event *event, kc_item * item ); void kc_change_invert( kc_menu *menu, kc_item * item ); #ifdef TABLE_CREATION int find_item_at( kc_item * items, int nitems, int x, int y ) { int i; for (i=0; icv_bitmap.bm_h-1; x--; if ( x < 0 ) { x = grd_curcanv->cv_bitmap.bm_w-1; } } i = find_item_at( items, nitems, x, y ); } while ( i < 0 ); return i; } int find_next_item_down( kc_item * items, int nitems, int citem ) { int x, y, i; y = items[citem].y; x = items[citem].x+items[citem].w1; do { y++; if ( y > grd_curcanv->cv_bitmap.bm_h-1 ) { y = 0; x++; if ( x > grd_curcanv->cv_bitmap.bm_w-1 ) { x = 0; } } i = find_item_at( items, nitems, x, y ); } while ( i < 0 ); return i; } int find_next_item_right( kc_item * items, int nitems, int citem ) { int x, y, i; y = items[citem].y; x = items[citem].x+items[citem].w1; do { x++; if ( x > grd_curcanv->cv_bitmap.bm_w-1 ) { x = 0; y++; if ( y > grd_curcanv->cv_bitmap.bm_h-1 ) { y = 0; } } i = find_item_at( items, nitems, x, y ); } while ( i < 0 ); return i; } int find_next_item_left( kc_item * items, int nitems, int citem ) { int x, y, i; y = items[citem].y; x = items[citem].x+items[citem].w1; do { x--; if ( x < 0 ) { x = grd_curcanv->cv_bitmap.bm_w-1; y--; if ( y < 0 ) { y = grd_curcanv->cv_bitmap.bm_h-1; } } i = find_item_at( items, nitems, x, y ); } while ( i < 0 ); return i; } #endif int get_item_height(kc_item *item) { int w, h, aw; char btext[10]; if (item->value==255) { strcpy(btext, ""); } else { switch( item->type ) { case BT_KEY: strncpy( btext, key_properties[item->value].key_text, 10 ); break; case BT_MOUSE_BUTTON: strncpy( btext, mousebutton_text[item->value], 10); break; case BT_MOUSE_AXIS: strncpy( btext, mouseaxis_text[item->value], 10 ); break; case BT_JOY_BUTTON: if (joybutton_text[item->value]) strncpy(btext, joybutton_text[item->value], 10); else sprintf(btext, "BTN%2d", item->value + 1); break; case BT_JOY_AXIS: if (joyaxis_text[item->value]) strncpy(btext, joyaxis_text[item->value], 10); else sprintf(btext, "AXIS%2d", item->value + 1); break; case BT_INVERT: strncpy( btext, invert_text[item->value], 10 ); break; } } gr_get_string_size(btext, &w, &h, &aw ); return h; } void kc_drawquestion( kc_menu *menu, kc_item *item ); void kconfig_draw(kc_menu *menu) { grs_canvas * save_canvas = grd_curcanv; grs_font * save_font; char * p; int i; int w = FSPACX(290), h = FSPACY(170); gr_set_current_canvas(NULL); nm_draw_background(((SWIDTH-w)/2)-BORDERX,((SHEIGHT-h)/2)-BORDERY,((SWIDTH-w)/2)+w+BORDERX,((SHEIGHT-h)/2)+h+BORDERY); gr_set_current_canvas(window_get_canvas(menu->wind)); save_font = grd_curcanv->cv_font; grd_curcanv->cv_font = MEDIUM3_FONT; p = strchr( menu->title, '\n' ); if ( p ) *p = 32; gr_string( 0x8000, FSPACY(8), menu->title ); if ( p ) *p = '\n'; grd_curcanv->cv_font = GAME_FONT; gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); gr_string( 0x8000, FSPACY(21), "Enter changes, ctrl-d deletes, ctrl-r resets defaults, ESC exits"); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); if ( menu->items == kc_keyboard ) { gr_set_fontcolor( BM_XRGB(31,27,6), -1 ); gr_setcolor( BM_XRGB(31,27,6) ); gr_rect( FSPACX( 98), FSPACY(42), FSPACX(106), FSPACY(42) ); // horiz/left gr_rect( FSPACX(120), FSPACY(42), FSPACX(128), FSPACY(42) ); // horiz/right gr_rect( FSPACX( 98), FSPACY(42), FSPACX( 98), FSPACY(44) ); // vert/left gr_rect( FSPACX(128), FSPACY(42), FSPACX(128), FSPACY(44) ); // vert/right gr_string( FSPACX(109), FSPACY(40), "OR" ); gr_rect( FSPACX(253), FSPACY(42), FSPACX(261), FSPACY(42) ); // horiz/left gr_rect( FSPACX(275), FSPACY(42), FSPACX(283), FSPACY(42) ); // horiz/right gr_rect( FSPACX(253), FSPACY(42), FSPACX(253), FSPACY(44) ); // vert/left gr_rect( FSPACX(283), FSPACY(42), FSPACX(283), FSPACY(44) ); // vert/right gr_string( FSPACX(264), FSPACY(40), "OR" ); } else if ( menu->items == kc_joystick ) { gr_set_fontcolor( BM_XRGB(31,27,6), -1 ); gr_setcolor( BM_XRGB(31,27,6) ); gr_string( 0x8000, FSPACY(30), TXT_BUTTONS ); gr_string( 0x8000,FSPACY(137), TXT_AXES ); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); gr_string( FSPACX( 81), FSPACY(145), TXT_AXIS ); gr_string( FSPACX(111), FSPACY(145), TXT_INVERT ); gr_string( FSPACX(230), FSPACY(145), TXT_AXIS ); gr_string( FSPACX(260), FSPACY(145), TXT_INVERT ); gr_set_fontcolor( BM_XRGB(31,27,6), -1 ); gr_setcolor( BM_XRGB(31,27,6) ); gr_rect( FSPACX(115), FSPACY(40), FSPACX(123), FSPACY(40) ); // horiz/left gr_rect( FSPACX(137), FSPACY(40), FSPACX(145), FSPACY(40) ); // horiz/right gr_rect( FSPACX(115), FSPACY(40), FSPACX(115), FSPACY(42) ); // vert/left gr_rect( FSPACX(145), FSPACY(40), FSPACX(145), FSPACY(42) ); // vert/right gr_string( FSPACX(126), FSPACY(38), "OR" ); gr_rect( FSPACX(261), FSPACY(40), FSPACX(269), FSPACY(40) ); // horiz/left gr_rect( FSPACX(283), FSPACY(40), FSPACX(291), FSPACY(40) ); // horiz/right gr_rect( FSPACX(261), FSPACY(40), FSPACX(261), FSPACY(42) ); // vert/left gr_rect( FSPACX(291), FSPACY(40), FSPACX(291), FSPACY(42) ); // vert/right gr_string( FSPACX(272), FSPACY(38), "OR" ); } else if ( menu->items == kc_mouse ) { gr_set_fontcolor( BM_XRGB(31,27,6), -1 ); gr_setcolor( BM_XRGB(31,27,6) ); gr_string( 0x8000, FSPACY(35), TXT_BUTTONS ); gr_string( 0x8000,FSPACY(137), TXT_AXES ); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); gr_string( FSPACX( 87), FSPACY(145), TXT_AXIS ); gr_string( FSPACX(120), FSPACY(145), TXT_INVERT ); gr_string( FSPACX(242), FSPACY(145), TXT_AXIS ); gr_string( FSPACX(274), FSPACY(145), TXT_INVERT ); } else if ( menu->items == kc_d1x ) { gr_set_fontcolor( BM_XRGB(31,27,6), -1 ); gr_setcolor( BM_XRGB(31,27,6) ); gr_string(FSPACX(152), FSPACY(60), "KEYBOARD"); gr_string(FSPACX(210), FSPACY(60), "JOYSTICK"); gr_string(FSPACX(273), FSPACY(60), "MOUSE"); } for (i=0; initems; i++ ) { kc_drawitem( &menu->items[i], 0 ); } kc_drawitem( &menu->items[menu->citem], 1 ); if (menu->changing) { switch( menu->items[menu->citem].type ) { case BT_KEY: gr_string( 0x8000, FSPACY(INFO_Y), TXT_PRESS_NEW_KEY ); break; case BT_MOUSE_BUTTON: gr_string( 0x8000, FSPACY(INFO_Y), TXT_PRESS_NEW_MBUTTON ); break; case BT_MOUSE_AXIS: gr_string( 0x8000, FSPACY(INFO_Y), TXT_MOVE_NEW_MSE_AXIS ); break; case BT_JOY_BUTTON: gr_string( 0x8000, FSPACY(INFO_Y), TXT_PRESS_NEW_JBUTTON ); break; case BT_JOY_AXIS: gr_string( 0x8000, FSPACY(INFO_Y), TXT_MOVE_NEW_JOY_AXIS ); break; } kc_drawquestion( menu, &menu->items[menu->citem] ); } gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); grd_curcanv->cv_font = save_font; gr_set_current_canvas( save_canvas ); } void kconfig_start_changing(kc_menu *menu) { if (menu->items[menu->citem].type == BT_INVERT) { kc_change_invert(menu, &menu->items[menu->citem]); return; } menu->q_fade_i = 0; // start question mark flasher menu->changing = 1; } int kconfig_mouse(window *wind, d_event *event, kc_menu *menu) { grs_canvas * save_canvas = grd_curcanv; int mx, my, mz, x1, x2, y1, y2; int i; int rval = 0; gr_set_current_canvas(window_get_canvas(wind)); if (menu->mouse_state) { int item_height; mouse_get_pos(&mx, &my, &mz); for (i=0; initems; i++ ) { item_height = get_item_height( &menu->items[i] ); x1 = grd_curcanv->cv_bitmap.bm_x + FSPACX(menu->items[i].x) + FSPACX(menu->items[i].w1); x2 = x1 + FSPACX(menu->items[i].w2); y1 = grd_curcanv->cv_bitmap.bm_y + FSPACY(menu->items[i].y); y2 = y1 + item_height; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) { menu->citem = i; rval = 1; break; } } } else if (event->type == EVENT_MOUSE_BUTTON_UP) { int item_height; mouse_get_pos(&mx, &my, &mz); item_height = get_item_height( &menu->items[menu->citem] ); x1 = grd_curcanv->cv_bitmap.bm_x + FSPACX(menu->items[menu->citem].x) + FSPACX(menu->items[menu->citem].w1); x2 = x1 + FSPACX(menu->items[menu->citem].w2); y1 = grd_curcanv->cv_bitmap.bm_y + FSPACY(menu->items[menu->citem].y); y2 = y1 + item_height; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) { kconfig_start_changing(menu); rval = 1; } else { // Click out of changing mode - kreatordxx menu->changing = 0; rval = 1; } } gr_set_current_canvas(save_canvas); return rval; } int kconfig_key_command(window *wind, d_event *event, kc_menu *menu) { int i,k; k = event_key_get(event); // when changing, process no keys instead of ESC if (menu->changing && (k != -2 && k != KEY_ESC)) return 0; switch (k) { case KEY_CTRLED+KEY_D: menu->items[menu->citem].value = 255; return 1; case KEY_CTRLED+KEY_R: if ( menu->items==kc_keyboard ) for (i=0; iitems[i].value=DefaultKeySettings[0][i]; if ( menu->items==kc_joystick ) for (i=0; iitems[i].value = DefaultKeySettings[1][i]; if ( menu->items==kc_mouse ) for (i=0; iitems[i].value = DefaultKeySettings[2][i]; if ( menu->items==kc_d1x ) for(i=0;iitems[i].value=DefaultKeySettingsD1X[i]; return 1; case KEY_DELETE: menu->items[menu->citem].value=255; return 1; case KEY_UP: case KEY_PAD8: #ifdef TABLE_CREATION if (menu->items[menu->citem].u==-1) menu->items[menu->citem].u=find_next_item_up( menu->items,menu->nitems, menu->citem); #endif menu->citem = menu->items[menu->citem].u; return 1; case KEY_DOWN: case KEY_PAD2: #ifdef TABLE_CREATION if (menu->items[menu->citem].d==-1) menu->items[menu->citem].d=find_next_item_down( menu->items,menu->nitems, menu->citem); #endif menu->citem = menu->items[menu->citem].d; return 1; case KEY_LEFT: case KEY_PAD4: #ifdef TABLE_CREATION if (menu->items[menu->citem].l==-1) menu->items[menu->citem].l=find_next_item_left( menu->items,menu->nitems, menu->citem); #endif menu->citem = menu->items[menu->citem].l; return 1; case KEY_RIGHT: case KEY_PAD6: #ifdef TABLE_CREATION if (menu->items[menu->citem].r==-1) menu->items[menu->citem].r=find_next_item_right( menu->items,menu->nitems, menu->citem); #endif menu->citem = menu->items[menu->citem].r; return 1; case KEY_ENTER: case KEY_PADENTER: kconfig_start_changing(menu); return 1; case -2: case KEY_ESC: if (menu->changing) menu->changing = 0; else window_close(wind); return 1; #ifdef TABLE_CREATION case KEY_F12: { static const char *const btype_text[] = { "BT_KEY", "BT_MOUSE_BUTTON", "BT_MOUSE_AXIS", "BT_JOY_BUTTON", "BT_JOY_AXIS", "BT_INVERT" }; PHYSFS_file * fp; for (i=0; itype) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); break; case EVENT_WINDOW_DEACTIVATED: menu->mouse_state = 0; break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: if (menu->changing && (menu->items[menu->citem].type == BT_MOUSE_BUTTON) && (event->type == EVENT_MOUSE_BUTTON_DOWN)) { kc_change_mousebutton( menu, event, &menu->items[menu->citem] ); menu->mouse_state = 1; return 1; } if (event_mouse_get_button(event) == MBTN_RIGHT) { if (!menu->changing) window_close(wind); return 1; } else if (event_mouse_get_button(event) != MBTN_LEFT) return 0; menu->mouse_state = (event->type == EVENT_MOUSE_BUTTON_DOWN); return kconfig_mouse(wind, event, menu); case EVENT_MOUSE_MOVED: if (menu->changing && menu->items[menu->citem].type == BT_MOUSE_AXIS) kc_change_mouseaxis(menu, event, &menu->items[menu->citem]); else event_mouse_get_delta( event, &menu->old_maxis[0], &menu->old_maxis[1], &menu->old_maxis[2]); break; case EVENT_JOYSTICK_BUTTON_DOWN: if (menu->changing && menu->items[menu->citem].type == BT_JOY_BUTTON) kc_change_joybutton(menu, event, &menu->items[menu->citem]); break; case EVENT_JOYSTICK_MOVED: if (menu->changing && menu->items[menu->citem].type == BT_JOY_AXIS) kc_change_joyaxis(menu, event, &menu->items[menu->citem]); else { int axis, value; event_joystick_get_axis( event, &axis, &value ); menu->old_jaxis[axis] = value; } break; case EVENT_KEY_COMMAND: { int rval = kconfig_key_command(wind, event, menu); if (rval) return rval; if (menu->changing && menu->items[menu->citem].type == BT_KEY) kc_change_key(menu, event, &menu->items[menu->citem]); return 0; } case EVENT_IDLE: kconfig_mouse(wind, event, menu); break; case EVENT_WINDOW_DRAW: if (menu->changing) timer_delay(f0_1/10); else timer_delay2(50); kconfig_draw(menu); break; case EVENT_WINDOW_CLOSE: d_free(menu); // Update save values... for (i=0; iitems = items; menu->nitems = nitems; menu->title = title; menu->citem = 0; menu->changing = 0; menu->mouse_state = 0; if (!(menu->wind = window_create(&grd_curscreen->sc_canvas, (SWIDTH - FSPACX(320))/2, (SHEIGHT - FSPACY(200))/2, FSPACX(320), FSPACY(200), (int (*)(window *, d_event *, void *))kconfig_handler, menu))) d_free(menu); } void kc_drawitem( kc_item *item, int is_current ) { int x, w, h, aw; char btext[10]; if (is_current) gr_set_fontcolor( BM_XRGB(20,20,29), -1 ); else gr_set_fontcolor( BM_XRGB(15,15,24), -1 ); gr_string( FSPACX(item->x), FSPACY(item->y), item->text ); if (item->value==255) { strcpy( btext, "" ); } else { switch( item->type ) { case BT_KEY: strncpy( btext, key_properties[item->value].key_text, 10 ); break; case BT_MOUSE_BUTTON: strncpy( btext, mousebutton_text[item->value], 10 ); break; case BT_MOUSE_AXIS: strncpy( btext, mouseaxis_text[item->value], 10 ); break; case BT_JOY_BUTTON: if (joybutton_text[item->value]) strncpy(btext, joybutton_text[item->value], 10); else sprintf(btext, "BTN%2d", item->value + 1); break; case BT_JOY_AXIS: if (joyaxis_text[item->value]) strncpy(btext, joyaxis_text[item->value], 10); else sprintf(btext, "AXIS%2d", item->value + 1); break; case BT_INVERT: strncpy( btext, invert_text[item->value], 10 ); break; } } gr_get_string_size(btext, &w, &h, &aw ); if (is_current) gr_setcolor( BM_XRGB(21,0,24) ); else gr_setcolor( BM_XRGB(16,0,19) ); gr_urect( FSPACX(item->w1+item->x), FSPACY(item->y-1), FSPACX(item->w1+item->x+item->w2), FSPACY(item->y)+h ); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); x = FSPACX(item->w1+item->x)+((FSPACX(item->w2)-w)/2); gr_string( x, FSPACY(item->y), btext ); } void kc_drawquestion( kc_menu *menu, kc_item *item ) { int c, x, w, h, aw; gr_get_string_size("?", &w, &h, &aw ); c = BM_XRGB(21,0,24); gr_setcolor( gr_fade_table[fades[menu->q_fade_i]*256+c] ); menu->q_fade_i++; if (menu->q_fade_i>63) menu->q_fade_i=0; gr_urect( FSPACX(item->w1+item->x), FSPACY(item->y-1), FSPACX(item->w1+item->x+item->w2), FSPACY(item->y)+h ); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); x = FSPACX(item->w1+item->x)+((FSPACX(item->w2)-w)/2); gr_string( x, FSPACY(item->y), "?" ); } void kc_change_key( kc_menu *menu, d_event *event, kc_item * item ) { int i,n; ubyte keycode = 255; Assert(event->type == EVENT_KEY_COMMAND); keycode = event_key_get_raw(event); if (!(key_properties[keycode].key_text)) return; for (n=0; n<(GameArg.CtlNoStickyKeys?sizeof(system_keys)-3:sizeof(system_keys)); n++ ) if ( system_keys[n] == keycode ) return; for (i=0; initems; i++ ) { n = item - menu->items; if ( (i!=n) && (menu->items[i].type==BT_KEY) && (menu->items[i].value==keycode) ) { menu->items[i].value = 255; } } item->value = keycode; menu->changing = 0; } void kc_change_joybutton( kc_menu *menu, d_event *event, kc_item * item ) { int n,i,button = 255; Assert(event->type == EVENT_JOYSTICK_BUTTON_DOWN); button = event_joystick_get_button(event); for (i=0; initems; i++ ) { n = item - menu->items; if ( (i!=n) && (menu->items[i].type==BT_JOY_BUTTON) && (menu->items[i].value==button) ) menu->items[i].value = 255; } item->value = button; menu->changing = 0; } void kc_change_mousebutton( kc_menu *menu, d_event *event, kc_item * item ) { int n,i,button; Assert(event->type == EVENT_MOUSE_BUTTON_DOWN || event->type == EVENT_MOUSE_BUTTON_UP); button = event_mouse_get_button(event); for (i=0; initems; i++) { n = item - menu->items; if ( (i!=n) && (menu->items[i].type==BT_MOUSE_BUTTON) && (menu->items[i].value==button) ) menu->items[i].value = 255; } item->value = button; menu->changing = 0; } void kc_change_joyaxis( kc_menu *menu, d_event *event, kc_item * item ) { int i, n, axis, value; Assert(event->type == EVENT_JOYSTICK_MOVED); event_joystick_get_axis( event, &axis, &value ); if ( abs(value-menu->old_jaxis[axis])<32 ) return; con_printf(CON_DEBUG, "Axis Movement detected: Axis %i\n", axis); for (i=0; initems; i++ ) { n = item - menu->items; if ( (i!=n) && (menu->items[i].type==BT_JOY_AXIS) && (menu->items[i].value==axis) ) menu->items[i].value = 255; } item->value = axis; menu->changing = 0; } void kc_change_mouseaxis( kc_menu *menu, d_event *event, kc_item * item ) { int i, n, dx, dy, dz; ubyte code = 255; Assert(event->type == EVENT_MOUSE_MOVED); event_mouse_get_delta( event, &dx, &dy, &dz ); if ( abs(dx)>5 ) code = 0; if ( abs(dy)>5 ) code = 1; if ( abs(dz)>5 ) code = 2; if (code!=255) { for (i=0; initems; i++ ) { n = item - menu->items; if ( (i!=n) && (menu->items[i].type==BT_MOUSE_AXIS) && (menu->items[i].value==code) ) menu->items[i].value = 255; } item->value = code; menu->changing = 0; } } void kc_change_invert( kc_menu *menu, kc_item * item ) { if (item->value) item->value = 0; else item->value = 1; menu->changing = 0; // in case we were changing something else } #include "screens.h" void kconfig(int n, char * title) { set_screen_mode( SCREEN_MENU ); kc_set_controls(); switch(n) { case 0:kconfig_sub( kc_keyboard,NUM_KEY_CONTROLS, title); break; case 1:kconfig_sub( kc_joystick,NUM_JOYSTICK_CONTROLS,title); break; case 2:kconfig_sub( kc_mouse, NUM_MOUSE_CONTROLS, title); break; case 3:kconfig_sub( kc_d1x, NUM_D1X_CONTROLS, title ); break; default: Int3(); return; } } void kconfig_read_controls(d_event *event, int automap_flag) { int i = 0, j = 0, speed_factor = cheats.turbo?2:1; static fix64 mouse_delta_time = 0; #ifndef NDEBUG // --- Don't do anything if in debug mode --- if ( keyd_pressed[KEY_DELETE] ) { memset( &Controls, 0, sizeof(control_info) ); return; } #endif Controls.pitch_time = Controls.vertical_thrust_time = Controls.heading_time = Controls.sideways_thrust_time = Controls.bank_time = Controls.forward_thrust_time = 0; switch (event->type) { case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: for (i = 0; i < NUM_KEY_CONTROLS; i++) { if (kc_keyboard[i].value < 255 && kc_keyboard[i].value == event_key_get_raw(event)) { if (kc_keyboard[i].ci_state_ptr != NULL) { if (event->type==EVENT_KEY_COMMAND) *kc_keyboard[i].ci_state_ptr |= kc_keyboard[i].state_bit; else *kc_keyboard[i].ci_state_ptr &= ~kc_keyboard[i].state_bit; } if (kc_keyboard[i].ci_count_ptr != NULL && event->type==EVENT_KEY_COMMAND) *kc_keyboard[i].ci_count_ptr += 1; } } if (!automap_flag && event->type == EVENT_KEY_COMMAND) for (i = 0, j = 0; i < 28; i += 3, j++) if (kc_d1x[i].value < 255 && kc_d1x[i].value == event_key_get_raw(event)) { Controls.select_weapon_count = j+1; break; } break; case EVENT_JOYSTICK_BUTTON_DOWN: case EVENT_JOYSTICK_BUTTON_UP: if (!(PlayerCfg.ControlType & CONTROL_USING_JOYSTICK)) break; for (i = 0; i < NUM_JOYSTICK_CONTROLS; i++) { if (kc_joystick[i].value < 255 && kc_joystick[i].type == BT_JOY_BUTTON && kc_joystick[i].value == event_joystick_get_button(event)) { if (kc_joystick[i].ci_state_ptr != NULL) { if (event->type==EVENT_JOYSTICK_BUTTON_DOWN) *kc_joystick[i].ci_state_ptr |= kc_joystick[i].state_bit; else *kc_joystick[i].ci_state_ptr &= ~kc_joystick[i].state_bit; } if (kc_joystick[i].ci_count_ptr != NULL && event->type==EVENT_JOYSTICK_BUTTON_DOWN) *kc_joystick[i].ci_count_ptr += 1; } } if (!automap_flag && event->type == EVENT_JOYSTICK_BUTTON_DOWN) for (i = 1, j = 0; i < 29; i += 3, j++) if (kc_d1x[i].value < 255 && kc_d1x[i].value == event_joystick_get_button(event)) { Controls.select_weapon_count = j+1; break; } break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: if (!(PlayerCfg.ControlType & CONTROL_USING_MOUSE)) break; for (i = 0; i < NUM_MOUSE_CONTROLS; i++) { if (kc_mouse[i].value < 255 && kc_mouse[i].type == BT_MOUSE_BUTTON && kc_mouse[i].value == event_mouse_get_button(event)) { if (kc_mouse[i].ci_state_ptr != NULL) { if (event->type==EVENT_MOUSE_BUTTON_DOWN) *kc_mouse[i].ci_state_ptr |= kc_mouse[i].state_bit; else *kc_mouse[i].ci_state_ptr &= ~kc_mouse[i].state_bit; } if (kc_mouse[i].ci_count_ptr != NULL && event->type==EVENT_MOUSE_BUTTON_DOWN) *kc_mouse[i].ci_count_ptr += 1; } } if (!automap_flag && event->type == EVENT_MOUSE_BUTTON_DOWN) for (i = 2, j = 0; i < 30; i += 3, j++) if (kc_d1x[i].value < 255 && kc_d1x[i].value == event_mouse_get_button(event)) { Controls.select_weapon_count = j+1; break; } break; case EVENT_JOYSTICK_MOVED: { int axis = 0, value = 0, joy_null_value = 0; if (!(PlayerCfg.ControlType & CONTROL_USING_JOYSTICK)) break; event_joystick_get_axis(event, &axis, &value); Controls.raw_joy_axis[axis] = value; if (axis == kc_joystick[13].value) // Pitch U/D Deadzone joy_null_value = PlayerCfg.JoystickDead[1]*8; if (axis == kc_joystick[15].value) // Turn L/R Deadzone joy_null_value = PlayerCfg.JoystickDead[0]*8; if (axis == kc_joystick[17].value) // Slide L/R Deadzone joy_null_value = PlayerCfg.JoystickDead[2]*8; if (axis == kc_joystick[19].value) // Slide U/D Deadzone joy_null_value = PlayerCfg.JoystickDead[3]*8; if (axis == kc_joystick[21].value) // Bank Deadzone joy_null_value = PlayerCfg.JoystickDead[4]*8; if (axis == kc_joystick[23].value) // Throttle - default deadzone joy_null_value = PlayerCfg.JoystickDead[5]*3; if (Controls.raw_joy_axis[axis] > joy_null_value) Controls.raw_joy_axis[axis] = ((Controls.raw_joy_axis[axis]-joy_null_value)*128)/(128-joy_null_value); else if (Controls.raw_joy_axis[axis] < -joy_null_value) Controls.raw_joy_axis[axis] = ((Controls.raw_joy_axis[axis]+joy_null_value)*128)/(128-joy_null_value); else Controls.raw_joy_axis[axis] = 0; Controls.joy_axis[axis] = (Controls.raw_joy_axis[axis]*FrameTime)/128; break; } case EVENT_MOUSE_MOVED: { if (!(PlayerCfg.ControlType & CONTROL_USING_MOUSE)) break; if (PlayerCfg.MouseFlightSim) { int ax[3]; event_mouse_get_delta( event, &ax[0], &ax[1], &ax[2] ); for (i = 0; i <= 2; i++) { int mouse_null_value = (i==2?16:PlayerCfg.MouseFSDead*8); Controls.raw_mouse_axis[i] += ax[i]; if (Controls.raw_mouse_axis[i] < -MOUSEFS_DELTA_RANGE) Controls.raw_mouse_axis[i] = -MOUSEFS_DELTA_RANGE; if (Controls.raw_mouse_axis[i] > MOUSEFS_DELTA_RANGE) Controls.raw_mouse_axis[i] = MOUSEFS_DELTA_RANGE; if (Controls.raw_mouse_axis[i] > mouse_null_value) Controls.mouse_axis[i] = (((Controls.raw_mouse_axis[i]-mouse_null_value)*MOUSEFS_DELTA_RANGE)/(MOUSEFS_DELTA_RANGE-mouse_null_value)*FrameTime)/MOUSEFS_DELTA_RANGE; else if (Controls.raw_mouse_axis[i] < -mouse_null_value) Controls.mouse_axis[i] = (((Controls.raw_mouse_axis[i]+mouse_null_value)*MOUSEFS_DELTA_RANGE)/(MOUSEFS_DELTA_RANGE-mouse_null_value)*FrameTime)/MOUSEFS_DELTA_RANGE; else Controls.mouse_axis[i] = 0; } } else { event_mouse_get_delta( event, &Controls.raw_mouse_axis[0], &Controls.raw_mouse_axis[1], &Controls.raw_mouse_axis[2] ); Controls.mouse_axis[0] = (Controls.raw_mouse_axis[0]*FrameTime)/8; Controls.mouse_axis[1] = (Controls.raw_mouse_axis[1]*FrameTime)/8; Controls.mouse_axis[2] = (Controls.raw_mouse_axis[2]*FrameTime); mouse_delta_time = timer_query() + (F1_0/30); } break; } case EVENT_IDLE: default: if (!PlayerCfg.MouseFlightSim && mouse_delta_time < timer_query()) { Controls.mouse_axis[0] = Controls.mouse_axis[1] = Controls.mouse_axis[2] = 0; mouse_delta_time = timer_query() + (F1_0/30); } break; } //------------ Read pitch_time ----------- if ( !Controls.slide_on_state ) { // From keyboard... if ( Controls.key_pitch_forward_state ) { if ( Controls.key_pitch_forward_down_time < F1_0 ) Controls.key_pitch_forward_down_time += (!Controls.key_pitch_forward_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[1]/16)+1:FrameTime/4; Controls.pitch_time += speed_factor*FrameTime/2*(Controls.key_pitch_forward_down_time/F1_0); } else Controls.key_pitch_forward_down_time = 0; if ( Controls.key_pitch_backward_state ) { if ( Controls.key_pitch_backward_down_time < F1_0 ) Controls.key_pitch_backward_down_time += (!Controls.key_pitch_backward_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[1]/16)+1:FrameTime/4; Controls.pitch_time -= speed_factor*FrameTime/2*(Controls.key_pitch_backward_down_time/F1_0); } else Controls.key_pitch_backward_down_time = 0; // From joystick... if ( !kc_joystick[14].value ) // If not inverted... Controls.pitch_time -= (Controls.joy_axis[kc_joystick[13].value]*PlayerCfg.JoystickSens[1])/8; else Controls.pitch_time += (Controls.joy_axis[kc_joystick[13].value]*PlayerCfg.JoystickSens[1])/8; // From mouse... if ( !kc_mouse[14].value ) // If not inverted... Controls.pitch_time -= (Controls.mouse_axis[kc_mouse[13].value]*PlayerCfg.MouseSens[1])/8; else Controls.pitch_time += (Controls.mouse_axis[kc_mouse[13].value]*PlayerCfg.MouseSens[1])/8; } else Controls.pitch_time = 0; //----------- Read vertical_thrust_time ----------------- if ( Controls.slide_on_state ) { // From keyboard... if ( Controls.key_pitch_forward_state ) { if (Controls.key_pitch_forward_down_time < F1_0) Controls.key_pitch_forward_down_time += (!Controls.key_pitch_forward_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[3]/16)+1:FrameTime/4; Controls.vertical_thrust_time += speed_factor*FrameTime*(Controls.key_pitch_forward_down_time/F1_0); } else Controls.key_pitch_forward_down_time = 0; if ( Controls.key_pitch_backward_state ) { if ( Controls.key_pitch_backward_down_time < F1_0 ) Controls.key_pitch_backward_down_time += (!Controls.key_pitch_backward_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[3]/16)+1:FrameTime/4; Controls.vertical_thrust_time -= speed_factor*FrameTime*(Controls.key_pitch_backward_down_time/F1_0); } else Controls.key_pitch_backward_down_time = 0; // From joystick... if ( !kc_joystick[20].value /*!kc_joystick[14].value*/ ) // If not inverted... NOTE: Use Slide U/D invert setting Controls.vertical_thrust_time += (Controls.joy_axis[kc_joystick[13].value]*PlayerCfg.JoystickSens[3])/8; else Controls.vertical_thrust_time -= (Controls.joy_axis[kc_joystick[13].value]*PlayerCfg.JoystickSens[3])/8; // From mouse... if ( !kc_mouse[20].value /*!kc_mouse[14].value*/ ) // If not inverted... NOTE: Use Slide U/D invert setting Controls.vertical_thrust_time -= (Controls.mouse_axis[kc_mouse[13].value]*PlayerCfg.MouseSens[3])/8; else Controls.vertical_thrust_time += (Controls.mouse_axis[kc_mouse[13].value]*PlayerCfg.MouseSens[3])/8; } // From keyboard... if ( Controls.key_slide_up_state ) { if (Controls.key_slide_up_down_time < F1_0) Controls.key_slide_up_down_time += (!Controls.key_slide_up_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[3]/16)+1:FrameTime/4; Controls.vertical_thrust_time += speed_factor*FrameTime*(Controls.key_slide_up_down_time/F1_0); } else Controls.key_slide_up_down_time = 0; if ( Controls.key_slide_down_state ) { if ( Controls.key_slide_down_down_time < F1_0 ) Controls.key_slide_down_down_time += (!Controls.key_slide_down_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[3]/16)+1:FrameTime/4; Controls.vertical_thrust_time -= speed_factor*FrameTime*(Controls.key_slide_down_down_time/F1_0); } else Controls.key_slide_down_down_time = 0; // From buttons... if ( Controls.btn_slide_up_state ) Controls.vertical_thrust_time += speed_factor*FrameTime; if ( Controls.btn_slide_down_state ) Controls.vertical_thrust_time -= speed_factor*FrameTime; // From joystick... if ( !kc_joystick[20].value ) // If not inverted... Controls.vertical_thrust_time += (Controls.joy_axis[kc_joystick[19].value]*PlayerCfg.JoystickSens[3])/8; else Controls.vertical_thrust_time -= (Controls.joy_axis[kc_joystick[19].value]*PlayerCfg.JoystickSens[3])/8; // From mouse... if ( !kc_mouse[20].value ) // If not inverted... Controls.vertical_thrust_time += (Controls.mouse_axis[kc_mouse[19].value]*PlayerCfg.MouseSens[3])/8; else Controls.vertical_thrust_time -= (Controls.mouse_axis[kc_mouse[19].value]*PlayerCfg.MouseSens[3])/8; //---------- Read heading_time ----------- if (!Controls.slide_on_state && !Controls.bank_on_state) { // From keyboard... if ( Controls.key_heading_right_state ) { if (Controls.key_heading_right_down_time < F1_0) Controls.key_heading_right_down_time += (!Controls.key_heading_right_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[0]/16)+1:FrameTime/4; Controls.heading_time += speed_factor*FrameTime*(Controls.key_heading_right_down_time/F1_0); } else Controls.key_heading_right_down_time = 0; if ( Controls.key_heading_left_state ) { if ( Controls.key_heading_left_down_time < F1_0 ) Controls.key_heading_left_down_time += (!Controls.key_heading_left_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[0]/16)+1:FrameTime/4; Controls.heading_time -= speed_factor*FrameTime*(Controls.key_heading_left_down_time/F1_0); } else Controls.key_heading_left_down_time = 0; // From joystick... if ( !kc_joystick[16].value ) // If not inverted... Controls.heading_time += (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[0])/8; else Controls.heading_time -= (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[0])/8; // From mouse... if ( !kc_mouse[16].value ) // If not inverted... Controls.heading_time += (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[0])/8; else Controls.heading_time -= (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[0])/8; } else Controls.heading_time = 0; //----------- Read sideways_thrust_time ----------------- if ( Controls.slide_on_state ) { // From keyboard... if ( Controls.key_heading_right_state ) { if (Controls.key_heading_right_down_time < F1_0) Controls.key_heading_right_down_time += (!Controls.key_heading_right_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[2]/16)+1:FrameTime/4; Controls.sideways_thrust_time += speed_factor*FrameTime*(Controls.key_heading_right_down_time/F1_0); } else Controls.key_heading_right_down_time = 0; if ( Controls.key_heading_left_state ) { if ( Controls.key_heading_left_down_time < F1_0 ) Controls.key_heading_left_down_time += (!Controls.key_heading_left_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[2]/16)+1:FrameTime/4; Controls.sideways_thrust_time -= speed_factor*FrameTime*(Controls.key_heading_left_down_time/F1_0); } else Controls.key_heading_left_down_time = 0; // From joystick... if ( !kc_joystick[18].value /*!kc_joystick[16].value*/ ) // If not inverted... NOTE: Use Slide L/R invert setting Controls.sideways_thrust_time += (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[2])/8; else Controls.sideways_thrust_time -= (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[2])/8; // From mouse... if ( !kc_mouse[18].value /*!kc_mouse[16].value*/ ) // If not inverted... NOTE: Use Slide L/R invert setting Controls.sideways_thrust_time += (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[2])/8; else Controls.sideways_thrust_time -= (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[2])/8; } // From keyboard... if ( Controls.key_slide_right_state ) { if (Controls.key_slide_right_down_time < F1_0) Controls.key_slide_right_down_time += (!Controls.key_slide_right_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[2]/16)+1:FrameTime/4; Controls.sideways_thrust_time += speed_factor*FrameTime*(Controls.key_slide_right_down_time/F1_0); } else Controls.key_slide_right_down_time = 0; if ( Controls.key_slide_left_state ) { if ( Controls.key_slide_left_down_time < F1_0 ) Controls.key_slide_left_down_time += (!Controls.key_slide_left_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[1]/16)+1:FrameTime/4; Controls.sideways_thrust_time -= speed_factor*FrameTime*(Controls.key_slide_left_down_time/F1_0); } else Controls.key_slide_left_down_time = 0; // From buttons... if ( Controls.btn_slide_left_state ) Controls.sideways_thrust_time -= speed_factor*FrameTime; if ( Controls.btn_slide_right_state ) Controls.sideways_thrust_time += speed_factor*FrameTime; // From joystick... if ( !kc_joystick[18].value ) // If not inverted... Controls.sideways_thrust_time += (Controls.joy_axis[kc_joystick[17].value]*PlayerCfg.JoystickSens[2])/8; else Controls.sideways_thrust_time -= (Controls.joy_axis[kc_joystick[17].value]*PlayerCfg.JoystickSens[2])/8; // From mouse... if ( !kc_mouse[18].value ) // If not inverted... Controls.sideways_thrust_time += (Controls.mouse_axis[kc_mouse[17].value]*PlayerCfg.MouseSens[2])/8; else Controls.sideways_thrust_time -= (Controls.mouse_axis[kc_mouse[17].value]*PlayerCfg.MouseSens[2])/8; //----------- Read bank_time ----------------- if ( Controls.bank_on_state ) { // From keyboard... if ( Controls.key_heading_left_state ) { if ( Controls.key_heading_left_down_time < F1_0 ) Controls.key_heading_left_down_time += (!Controls.key_heading_left_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[4]/16)+1:FrameTime/4; Controls.bank_time += speed_factor*FrameTime*(Controls.key_heading_left_down_time/F1_0); } else Controls.key_bank_left_down_time = 0; if ( Controls.key_heading_right_state ) { if (Controls.key_heading_right_down_time < F1_0) Controls.key_heading_right_down_time += (!Controls.key_heading_right_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[4]/16)+1:FrameTime/4; Controls.bank_time -= speed_factor*FrameTime*(Controls.key_heading_right_down_time/F1_0); } else Controls.key_heading_right_down_time = 0; // From joystick... if ( !kc_joystick[22].value /*!kc_joystick[16].value*/ ) // If not inverted... NOTE: Use Bank L/R invert setting Controls.bank_time -= (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[4])/8; else Controls.bank_time += (Controls.joy_axis[kc_joystick[15].value]*PlayerCfg.JoystickSens[4])/8; // From mouse... if ( !kc_mouse[22].value /*!kc_mouse[16].value*/ ) // If not inverted... NOTE: Use Bank L/R invert setting Controls.bank_time += (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[4])/8; else Controls.bank_time -= (Controls.mouse_axis[kc_mouse[15].value]*PlayerCfg.MouseSens[4])/8; } // From keyboard... if ( Controls.key_bank_left_state ) { if ( Controls.key_bank_left_down_time < F1_0 ) Controls.key_bank_left_down_time += (!Controls.key_bank_left_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[4]/16)+1:FrameTime/4; Controls.bank_time += speed_factor*FrameTime*(Controls.key_bank_left_down_time/F1_0); } else Controls.key_bank_left_down_time = 0; if ( Controls.key_bank_right_state ) { if (Controls.key_bank_right_down_time < F1_0) Controls.key_bank_right_down_time += (!Controls.key_bank_right_down_time)?F1_0*((float)PlayerCfg.KeyboardSens[4]/16)+1:FrameTime/4; Controls.bank_time -= speed_factor*FrameTime*(Controls.key_bank_right_down_time/F1_0); } else Controls.key_bank_right_down_time = 0; // From buttons... if ( Controls.btn_bank_left_state ) Controls.bank_time += speed_factor*FrameTime; if ( Controls.btn_bank_right_state ) Controls.bank_time -= speed_factor*FrameTime; // From joystick... if ( !kc_joystick[22].value ) // If not inverted... Controls.bank_time -= (Controls.joy_axis[kc_joystick[21].value]*PlayerCfg.JoystickSens[4])/8; else Controls.bank_time += (Controls.joy_axis[kc_joystick[21].value]*PlayerCfg.JoystickSens[4])/8; // From mouse... if ( !kc_mouse[22].value ) // If not inverted... Controls.bank_time += (Controls.mouse_axis[kc_mouse[21].value]*PlayerCfg.MouseSens[4])/8; else Controls.bank_time -= (Controls.mouse_axis[kc_mouse[21].value]*PlayerCfg.MouseSens[4])/8; //----------- Read forward_thrust_time ------------- // From keyboard/buttons... if ( Controls.accelerate_state ) Controls.forward_thrust_time += speed_factor*FrameTime; if ( Controls.reverse_state ) Controls.forward_thrust_time -= speed_factor*FrameTime; // From joystick... if ( !kc_joystick[24].value ) // If not inverted... Controls.forward_thrust_time -= (Controls.joy_axis[kc_joystick[23].value]*PlayerCfg.JoystickSens[5])/8; else Controls.forward_thrust_time += (Controls.joy_axis[kc_joystick[23].value]*PlayerCfg.JoystickSens[5])/8; // From mouse... if ( !kc_mouse[24].value ) // If not inverted... Controls.forward_thrust_time -= (Controls.mouse_axis[kc_mouse[23].value]*PlayerCfg.MouseSens[5])/8; else Controls.forward_thrust_time += (Controls.mouse_axis[kc_mouse[23].value]*PlayerCfg.MouseSens[5])/8; //----------- Read cruise-control-type of throttle. if ( Controls.cruise_plus_state ) Cruise_speed += speed_factor*FrameTime*80; if ( Controls.cruise_minus_state ) Cruise_speed -= speed_factor*FrameTime*80; if ( Controls.cruise_off_count > 0 ) Controls.cruise_off_count = Cruise_speed = 0; if (Cruise_speed > i2f(100) ) Cruise_speed = i2f(100); if (Cruise_speed < 0 ) Cruise_speed = 0; if (Controls.forward_thrust_time==0) Controls.forward_thrust_time = fixmul(Cruise_speed,FrameTime)/100; //----------- Clamp values between -FrameTime and FrameTime if (Controls.pitch_time > FrameTime/2 ) Controls.pitch_time = FrameTime/2; if (Controls.heading_time > FrameTime ) Controls.heading_time = FrameTime; if (Controls.pitch_time < -FrameTime/2 ) Controls.pitch_time = -FrameTime/2; if (Controls.heading_time < -FrameTime ) Controls.heading_time = -FrameTime; if (Controls.vertical_thrust_time > FrameTime ) Controls.vertical_thrust_time = FrameTime; if (Controls.sideways_thrust_time > FrameTime ) Controls.sideways_thrust_time = FrameTime; if (Controls.bank_time > FrameTime ) Controls.bank_time = FrameTime; if (Controls.forward_thrust_time > FrameTime ) Controls.forward_thrust_time = FrameTime; if (Controls.vertical_thrust_time < -FrameTime ) Controls.vertical_thrust_time = -FrameTime; if (Controls.sideways_thrust_time < -FrameTime ) Controls.sideways_thrust_time = -FrameTime; if (Controls.bank_time < -FrameTime ) Controls.bank_time = -FrameTime; if (Controls.forward_thrust_time < -FrameTime ) Controls.forward_thrust_time = -FrameTime; } void reset_cruise(void) { Cruise_speed=0; } void kc_set_controls() { int i; for (i=0; i #include #include #include #include #include "dxxerror.h" #include "pstypes.h" #include "gr.h" #include "window.h" #include "key.h" #include "palette.h" #include "game.h" #include "window.h" #include "gamefont.h" #include "u_mem.h" #include "newmenu.h" #include "menu.h" #include "player.h" #include "screens.h" #include "cntrlcen.h" #include "mouse.h" #include "joy.h" #include "timer.h" #include "text.h" #include "rbaudio.h" #include "multi.h" #include "kmatrix.h" #include "gauges.h" #include "pcx.h" #ifdef OGL #include "ogl_init.h" #endif #define CENTERING_OFFSET(x) ((300 - (70 + (x)*25 ))/2) #define CENTERSCREEN (SWIDTH/2) #define KMATRIX_VIEW_SEC 7 // Time after reactor explosion until new level - in seconds void kmatrix_redraw_coop(); fix64 StartAbortMenuTime; void kmatrix_draw_item( int i, int *sorted ) { int j, x, y; char temp[10]; y = FSPACY(50+i*9); gr_printf( FSPACX(CENTERING_OFFSET(N_players)), y, "%s", Players[sorted[i]].callsign ); for (j=0; jcv_font = GAME_FONT; gr_set_fontcolor(gr_find_closest_color(255,255,255),-1); if (reactor) gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Waiting for players to finish level. Reactor time: T-%d", time); else gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Level finished. Wait (%d) to proceed or ESC to Quit.", time); } typedef struct kmatrix_screen { grs_bitmap background; int network; fix64 end_time; int playing; } kmatrix_screen; void kmatrix_redraw(kmatrix_screen *km) { int i, color; int sorted[MAX_PLAYERS]; gr_set_current_canvas(NULL); show_fullscr(&km->background); if (Game_mode & GM_MULTI_COOP) { kmatrix_redraw_coop(); } else { multi_sort_kill_list(); grd_curcanv->cv_font = MEDIUM3_FONT; gr_string( 0x8000, FSPACY(10), TXT_KILL_MATRIX_TITLE); grd_curcanv->cv_font = GAME_FONT; multi_get_kill_list(sorted); kmatrix_draw_names(sorted); for (i=0; icv_font = MEDIUM3_FONT; gr_string( 0x8000, FSPACY(10), "COOPERATIVE SUMMARY"); grd_curcanv->cv_font = GAME_FONT; multi_get_kill_list(sorted); kmatrix_draw_coop_names(sorted); for (i=0; itype) { case EVENT_KEY_COMMAND: k = event_key_get(event); switch( k ) { case KEY_ESC: if (km->network) { StartAbortMenuTime=timer_query(); choice=nm_messagebox1( NULL,multi_endlevel_poll2, NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME ); } else choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME ); if (choice==0) { Players[Player_num].connected=CONNECT_DISCONNECTED; if (km->network) multi_send_endlevel_packet(); multi_leave_game(); window_close(wind); if (Game_wind) window_close(Game_wind); return 1; } return 1; default: break; } break; case EVENT_WINDOW_DRAW: timer_delay2(50); if (km->network) multi_do_protocol_frame(0, 1); km->playing = 0; // Check if all connected players are also looking at this screen ... for (i = 0; i < MAX_PLAYERS; i++) if (Players[i].connected) if (Players[i].connected != CONNECT_END_MENU && Players[i].connected != CONNECT_DIED_IN_MINE) km->playing = 1; // ... and let the reactor blow sky high! if (!km->playing) Countdown_seconds_left = -1; // If Reactor is finished and end_time not inited, set the time when we will exit this loop if (km->end_time == -1 && Countdown_seconds_left < 0 && !km->playing) km->end_time = timer_query() + (KMATRIX_VIEW_SEC * F1_0); // Check if end_time has been reached and exit loop if (timer_query() >= km->end_time && km->end_time != -1) { if (km->network) multi_send_endlevel_packet(); // make sure window_close(wind); break; } kmatrix_redraw(km); if (km->playing) kmatrix_status_msg(Countdown_seconds_left, 1); else kmatrix_status_msg(f2i(timer_query()-km->end_time), 0); break; case EVENT_WINDOW_CLOSE: game_flush_inputs(); newmenu_free_background(); break; default: break; } return 0; } void kmatrix_view(int network) { kmatrix_screen *km; window *wind; int i = 0; MALLOC(km, kmatrix_screen, 1); if (!km) return; gr_init_bitmap_data(&km->background); if (pcx_read_bitmap(STARS_BACKGROUND, &km->background, BM_LINEAR, gr_palette) != PCX_ERROR_NONE) { d_free(km); return; } gr_palette_load(gr_palette); km->network = network; km->end_time = -1; km->playing = 0; set_screen_mode( SCREEN_MENU ); game_flush_inputs(); for (i=0;isc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))kmatrix_handler, km); if (!wind) { d_free(km); return; } while (window_exists(wind)) event_process(); gr_free_bitmap_data(&km->background); d_free(km); } dxx-rebirth-0.58.1-d1x/main/kmatrix.h000066400000000000000000000015151217717257200173300ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Kill matrix. * */ #ifndef _KMATRIX_H #define _KMATRIX_H void kmatrix_view(int network); #endif dxx-rebirth-0.58.1-d1x/main/laser.c000066400000000000000000001416311217717257200167560ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * This will contain the laser code * */ #include #include #include "inferno.h" #include "game.h" #include "bm.h" #include "object.h" #include "laser.h" #include "segment.h" #include "fvi.h" #include "segpoint.h" #include "dxxerror.h" #include "key.h" #include "texmap.h" #include "textures.h" #include "render.h" #include "vclip.h" #include "fireball.h" #include "polyobj.h" #include "robot.h" #include "weapon.h" #include "timer.h" #include "player.h" #include "sounds.h" #include "ai.h" #include "powerup.h" #include "multi.h" #include "physics.h" #include "hudmsg.h" #define NEWHOMER int Network_laser_track = -1; int find_homing_object_complete(vms_vector *curpos, object *tracker, int track_obj_type1, int track_obj_type2); //--------------------------------------------------------------------------------- // Called by render code.... determines if the laser is from a robot or the // player and calls the appropriate routine. void Laser_render(object *obj) { // Commented out by John (sort of, typed by Mike) on 6/8/94 #if 0 switch( obj->id ) { case WEAPON_TYPE_WEAK_LASER: case WEAPON_TYPE_STRONG_LASER: case WEAPON_TYPE_CANNON_BALL: case WEAPON_TYPE_MISSILE: break; default: Error( "Invalid weapon type in Laser_render\n" ); } #endif switch( Weapon_info[obj->id].render_type ) { case WEAPON_RENDER_LASER: Int3(); // Not supported anymore! //Laser_draw_one(obj-Objects, Weapon_info[obj->id].bitmap ); break; case WEAPON_RENDER_BLOB: draw_object_blob(obj, Weapon_info[obj->id].bitmap ); break; case WEAPON_RENDER_POLYMODEL: break; case WEAPON_RENDER_VCLIP: Int3(); // Oops, not supported, type added by mk on 09/09/94, but not for lasers... default: Error( "Invalid weapon render type in Laser_render\n" ); } } //--------------------------------------------------------------------------------- // Draws a texture-mapped laser bolt //void Laser_draw_one( int objnum, grs_bitmap * bmp ) //{ // int t1, t2, t3; // g3s_point p1, p2; // object *obj; // vms_vector start_pos,end_pos; // // obj = &Objects[objnum]; // // start_pos = obj->pos; // vm_vec_scale_add(&end_pos,&start_pos,&obj->orient.fvec,-Laser_length); // // g3_rotate_point(&p1,&start_pos); // g3_rotate_point(&p2,&end_pos); // // t1 = Lighting_on; // t2 = Interpolation_method; // t3 = Transparency_on; // // Lighting_on = 0; // //Interpolation_method = 3; // Full perspective // Interpolation_method = 1; // Linear // Transparency_on = 1; // // //gr_setcolor( gr_getcolor(31,15,0)); // //g3_draw_line_ptrs(p1,p2); // //g3_draw_rod(p1,0x2000,p2,0x2000); // //g3_draw_rod(p1,Laser_width,p2,Laser_width); // g3_draw_rod_tmap(bmp,&p2,Laser_width,&p1,Laser_width,0); // Lighting_on = t1; // Interpolation_method = t2; // Transparency_on = t3; // //} // Changed by MK on 09/07/94 // I want you to be able to blow up your own bombs. // AND...Your proximity bombs can blow you up if they're 2.0 seconds or more old. int laser_are_related( int o1, int o2 ) { if ( (o1<0) || (o2<0) ) return 0; // See if o2 is the parent of o1 if ( Objects[o1].type == OBJ_WEAPON ) if ( (Objects[o1].ctype.laser_info.parent_num==o2) && (Objects[o1].ctype.laser_info.parent_signature==Objects[o2].signature) ) { // o1 is a weapon, o2 is the parent of 1, so if o1 is PROXIMITY_BOMB and o2 is player, they are related only if o1 < 2.0 seconds old if ((Objects[o1].id != PROXIMITY_ID) || (Objects[o1].ctype.laser_info.creation_time + F1_0*2 >= GameTime64)) { return 1; } else return 0; } // See if o1 is the parent of o2 if ( Objects[o2].type == OBJ_WEAPON ) if ( (Objects[o2].ctype.laser_info.parent_num==o1) && (Objects[o2].ctype.laser_info.parent_signature==Objects[o1].signature) ) return 1; // They must both be weapons if ( Objects[o1].type != OBJ_WEAPON || Objects[o2].type != OBJ_WEAPON ) return 0; // Here is the 09/07/94 change -- Siblings must be identical, others can hurt each other // See if they're siblings... if ( Objects[o1].ctype.laser_info.parent_signature==Objects[o2].ctype.laser_info.parent_signature ) { if (is_proximity_bomb_or_smart_mine(Objects[o1].id) || is_proximity_bomb_or_smart_mine(Objects[o2].id)) return 0; //if either is proximity, then can blow up, so say not related else return 1; } return 0; } void do_muzzle_stuff(int segnum, vms_vector *pos) { Muzzle_data[Muzzle_queue_index].create_time = timer_query(); Muzzle_data[Muzzle_queue_index].segnum = segnum; Muzzle_data[Muzzle_queue_index].pos = *pos; Muzzle_queue_index++; if (Muzzle_queue_index >= MUZZLE_QUEUE_MAX) Muzzle_queue_index = 0; } //--------------------------------------------------------------------------------- // Initializes a laser after Fire is pressed // Returns object number. int Laser_create_new( vms_vector * direction, vms_vector * position, int segnum, int parent, int weapon_type, int make_sound ) { int objnum; object *obj; int rtype=-1; fix parent_speed, weapon_speed; fix volume; fix laser_radius = -1; fix laser_length=0; Assert( weapon_type < N_weapon_types ); if ( (weapon_type<0) || (weapon_type>=N_weapon_types) ) weapon_type = 0; // Don't let homing blobs make muzzle flash. if (Objects[parent].type == OBJ_ROBOT) do_muzzle_stuff(segnum, position); switch( Weapon_info[weapon_type].render_type ) { case WEAPON_RENDER_BLOB: rtype = RT_LASER; // Render as a laser even if blob (see render code above for explanation) laser_radius = Weapon_info[weapon_type].blob_size; laser_length = 0; break; case WEAPON_RENDER_POLYMODEL: laser_radius = 0; // Filled in below. rtype = RT_POLYOBJ; break; case WEAPON_RENDER_LASER: Int3(); // Not supported anymore break; case WEAPON_RENDER_NONE: rtype = RT_NONE; laser_radius = F1_0; laser_length = 0; break; case WEAPON_RENDER_VCLIP: rtype = RT_WEAPON_VCLIP; laser_radius = Weapon_info[weapon_type].blob_size; laser_length = 0; break; default: Error( "Invalid weapon render type in Laser_create_new\n" ); } // Add to object list Assert(laser_radius != -1); Assert(rtype != -1); objnum = obj_create( OBJ_WEAPON, weapon_type, segnum, position, NULL, laser_radius, CT_WEAPON, MT_PHYSICS, rtype ); if ( objnum < 0 ) { Int3(); return -1; } obj = &Objects[objnum]; if (Objects[parent].type == OBJ_PLAYER) { if (weapon_type == FUSION_ID) { int fusion_scale; if (Game_mode & GM_MULTI) fusion_scale = 2; else fusion_scale = 4; if (Fusion_charge <= 0) obj->ctype.laser_info.multiplier = F1_0; else if (Fusion_charge <= F1_0*fusion_scale) obj->ctype.laser_info.multiplier = F1_0 + Fusion_charge/2; else obj->ctype.laser_info.multiplier = F1_0*fusion_scale; // Fusion damage was boosted by mk on 3/27 (for reg 1.1 release), but we only want it to apply to single player games. if (Game_mode & GM_MULTI) obj->ctype.laser_info.multiplier /= 2; } else if ((weapon_type == LASER_ID) && (Players[Objects[parent].id].flags & PLAYER_FLAGS_QUAD_LASERS)) obj->ctype.laser_info.multiplier = F1_0*3/4; } // This is strange: Make children of smart bomb bounce so if they hit a wall right away, they // won't detonate. The frame interval code will clear this bit after 1/2 second. if ((weapon_type == PLAYER_SMART_HOMING_ID) || (weapon_type == ROBOT_SMART_HOMING_ID)) obj->mtype.phys_info.flags |= PF_BOUNCE; if (Weapon_info[weapon_type].render_type == WEAPON_RENDER_POLYMODEL) { obj->rtype.pobj_info.model_num = Weapon_info[obj->id].model_num; laser_radius = fixdiv(Polygon_models[obj->rtype.pobj_info.model_num].rad,Weapon_info[obj->id].po_len_to_width_ratio); laser_length = Polygon_models[obj->rtype.pobj_info.model_num].rad * 2; obj->size = laser_radius; } obj->mtype.phys_info.mass = Weapon_info[weapon_type].mass; obj->mtype.phys_info.drag = Weapon_info[weapon_type].drag; if (Weapon_info[weapon_type].bounce) obj->mtype.phys_info.flags |= PF_BOUNCE; vm_vec_zero(&obj->mtype.phys_info.thrust); if (weapon_type == FLARE_ID) obj->mtype.phys_info.flags |= PF_STICK; //this obj sticks to walls obj->shields = Weapon_info[obj->id].strength[Difficulty_level]; // Fill in laser-specific data obj->lifeleft = Weapon_info[obj->id].lifetime; obj->ctype.laser_info.parent_type = Objects[parent].type; obj->ctype.laser_info.parent_signature = Objects[parent].signature; obj->ctype.laser_info.parent_num = parent; // Assign parent type to highest level creator. This propagates parent type down from // the original creator through weapons which create children of their own (ie, smart missile) if (Objects[parent].type == OBJ_WEAPON) { int highest_parent = parent; while (Objects[highest_parent].type == OBJ_WEAPON) { highest_parent = Objects[highest_parent].ctype.laser_info.parent_num; obj->ctype.laser_info.parent_num = highest_parent; obj->ctype.laser_info.parent_type = Objects[highest_parent].type; obj->ctype.laser_info.parent_signature = Objects[highest_parent].signature; } } // Create orientation matrix so we can look from this pov // Homing missiles also need an orientation matrix so they know if they can make a turn. if ((obj->render_type == RT_POLYOBJ) || (Weapon_info[obj->id].homing_flag)) vm_vector_2_matrix( &obj->orient,direction, &Objects[parent].orient.uvec ,NULL); if (( &Objects[parent] != Viewer ) && (Objects[parent].type != OBJ_WEAPON)) { // Muzzle flash if (Weapon_info[obj->id].flash_vclip > -1 ) object_create_muzzle_flash( obj->segnum, &obj->pos, Weapon_info[obj->id].flash_size, Weapon_info[obj->id].flash_vclip ); } // Re-enable, 09/09/94: volume = F1_0; if (Weapon_info[obj->id].flash_sound > -1 ) { if (make_sound) { if ( parent == (Viewer-Objects) ) { if (weapon_type == VULCAN_ID) // Make your own vulcan gun 1/2 as loud. volume = F1_0 / 2; digi_play_sample( Weapon_info[obj->id].flash_sound, volume ); } else { digi_link_sound_to_pos( Weapon_info[obj->id].flash_sound, obj->segnum, 0, &obj->pos, 0, volume ); } } } // WARNING! NOTE! HEY! DEBUG! ETC! --MK 10/26/94 // This is John's new code to fire the laser from the gun tip so that the back end of the laser bolt is // at the gun tip. A problem that needs to be fixed is that the laser bolt might be in another segment. // Use find_vector_interesection to detect the segment. // Move 1 frame, so that the end-tip of the laser is touching the gun barrel. // This also jitters the laser a bit so that it doesn't alias. // Don't do for weapons created by weapons. if ((Objects[parent].type != OBJ_WEAPON) && (Weapon_info[weapon_type].render_type != WEAPON_RENDER_NONE) && (weapon_type != FLARE_ID)) { // if ((Objects[parent].type != OBJ_WEAPON) && (weapon_type != FLARE_ID) ) { vms_vector end_pos; int end_segnum; vm_vec_scale_add( &end_pos, &obj->pos, direction, (laser_length/2) ); end_segnum = find_point_seg(&end_pos, obj->segnum); if (end_segnum != obj->segnum) { if (end_segnum != -1) { obj->pos = end_pos; obj_relink(obj-Objects, end_segnum); } } else obj->pos = end_pos; } // Here's where to fix the problem with objects which are moving backwards imparting higher velocity to their weaponfire. // Find out if moving backwards. if (is_proximity_bomb_or_smart_mine(weapon_type)) { parent_speed = vm_vec_mag_quick(&Objects[parent].mtype.phys_info.velocity); if (vm_vec_dot(&Objects[parent].mtype.phys_info.velocity, &Objects[parent].orient.fvec) < 0) parent_speed = -parent_speed; // if(parent_speed>(F1_0*60)) // parent_speed=F1_0*1600; /* { char *murp; sprintf(murp,"%i.%i",parent_speed>>16,(parent_speed<<16)>>16); nm_messagebox(NULL,1,"OK",murp); }*/ } else parent_speed = 0; weapon_speed = Weapon_info[obj->id].speed[Difficulty_level]; // Ugly hack (too bad we're on a deadline), for homing missiles dropped by smart bomb, start them out slower. if ((obj->id == PLAYER_SMART_HOMING_ID) || (obj->id == ROBOT_SMART_HOMING_ID)) weapon_speed /= 4; if (Weapon_info[obj->id].thrust != 0) weapon_speed /= 2; vm_vec_copy_scale( &obj->mtype.phys_info.velocity, direction, weapon_speed + parent_speed ); // Set thrust if (Weapon_info[weapon_type].thrust != 0) { obj->mtype.phys_info.thrust = obj->mtype.phys_info.velocity; vm_vec_scale(&obj->mtype.phys_info.thrust, fixdiv(Weapon_info[obj->id].thrust, weapon_speed+parent_speed)); } // THIS CODE MAY NOT BE NEEDED... it was used to move the lasers out of the gun, since the // laser pos is acutally the head of the laser, and we want the tail to be at the starting // point, not the head. // object_move_one( obj ); // This next, apparently redundant line, appears necessary due to a hack in render.c // obj->lifeleft = Weapon_info[obj->id].lifetime; if ((obj->type == OBJ_WEAPON) && (obj->id == FLARE_ID)) obj->lifeleft += (d_rand()-16384) << 2; // add in -2..2 seconds return objnum; } // ----------------------------------------------------------------------------------------------------------- // Calls Laser_create_new, but takes care of the segment and point computation for you. int Laser_create_new_easy( vms_vector * direction, vms_vector * position, int parent, int weapon_type, int make_sound ) { fvi_query fq; fvi_info hit_data; object *pobjp = &Objects[parent]; int fate; // Find segment containing laser fire position. If the robot is straddling a segment, the position from // which it fires may be in a different segment, which is bad news for find_vector_intersection. So, cast // a ray from the object center (whose segment we know) to the laser position. Then, in the call to Laser_create_new // use the data returned from this call to find_vector_intersection. // Note that while find_vector_intersection is pretty slow, it is not terribly slow if the destination point is // in the same segment as the source point. fq.p0 = &pobjp->pos; fq.startseg = pobjp->segnum; fq.p1 = position; fq.rad = 0; fq.thisobjnum = pobjp-Objects; fq.ignore_obj_list = NULL; fq.flags = FQ_TRANSWALL | FQ_CHECK_OBJS; //what about trans walls??? fate = find_vector_intersection(&fq, &hit_data); if (fate != HIT_NONE || hit_data.hit_seg==-1) { return -1; } return Laser_create_new( direction, &hit_data.hit_pnt, hit_data.hit_seg, parent, weapon_type, make_sound ); } int Muzzle_queue_index = 0; muzzle_info Muzzle_data[MUZZLE_QUEUE_MAX]; // ----------------------------------------------------------------------------------------------------------- // Determine if two objects are on a line of sight. If so, return true, else return false. // Calls fvi. int object_to_object_visibility(object *obj1, object *obj2, int trans_type) { fvi_query fq; fvi_info hit_data; int fate; fq.p0 = &obj1->pos; fq.startseg = obj1->segnum; fq.p1 = &obj2->pos; fq.rad = 0x10; fq.thisobjnum = obj1-Objects; fq.ignore_obj_list = NULL; fq.flags = trans_type; fate = find_vector_intersection(&fq, &hit_data); if (fate == HIT_WALL) return 0; else if (fate == HIT_NONE) return 1; else Int3(); // Contact Mike: Oops, what happened? What is fate? // 2 = hit object (impossible), 3 = bad starting point (bad) return 0; } fix Min_trackable_dot = 3*(F1_0 - MIN_TRACKABLE_DOT)/4 + MIN_TRACKABLE_DOT; //MIN_TRACKABLE_DOT; // ----------------------------------------------------------------------------------------------------------- // Return true if weapon *tracker is able to track object Objects[track_goal], else return false. // In order for the object to be trackable, it must be within a reasonable turning radius for the missile // and it must not be obstructed by a wall. int object_is_trackable(int track_goal, object *tracker, fix *dot) { vms_vector vector_to_goal; object *objp; if (track_goal == -1) return 0; if (Game_mode & GM_MULTI_COOP) return 0; objp = &Objects[track_goal]; // Don't track player if he's cloaked. if ((track_goal == Players[Player_num].objnum) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) return 0; // Can't track AI object if he's cloaked. if (objp->type == OBJ_ROBOT) if (objp->ctype.ai_info.CLOAKED) return 0; vm_vec_sub(&vector_to_goal, &objp->pos, &tracker->pos); vm_vec_normalize_quick(&vector_to_goal); *dot = vm_vec_dot(&vector_to_goal, &tracker->orient.fvec); if ((*dot < Min_trackable_dot) && (*dot > F1_0*9/10)) { vm_vec_normalize(&vector_to_goal); *dot = vm_vec_dot(&vector_to_goal, &tracker->orient.fvec); } if (*dot >= Min_trackable_dot) { int rval; // dot is in legal range, now see if object is visible rval = object_to_object_visibility(tracker, objp, FQ_TRANSWALL); return rval; } else { return 0; } } // -------------------------------------------------------------------------------------------- // Find object to home in on. // Scan list of objects rendered last frame, find one that satisfies function of nearness to center and distance. int find_homing_object(vms_vector *curpos, object *tracker) { int i; fix max_dot = -F1_0*2; int best_objnum = -1; if (!Weapon_info[tracker->id].homing_flag) { Int3(); // Contact Mike: This is a bad and stupid thing. Who called this routine with an illegal laser type?? return 0; // Track the damn stupid player for causing this problem! } // Find an object to track based on game mode (eg, whether in network play) and who fired it. if (Game_mode & GM_MULTI) { // In network mode. if (tracker->ctype.laser_info.parent_type == OBJ_PLAYER) { // It's fired by a player, so if robots present, track robot, else track player. if (Game_mode & GM_MULTI_COOP) return find_homing_object_complete( curpos, tracker, OBJ_ROBOT, -1); else return find_homing_object_complete( curpos, tracker, OBJ_PLAYER, OBJ_ROBOT); } else { Assert(tracker->ctype.laser_info.parent_type == OBJ_ROBOT); return find_homing_object_complete(curpos, tracker, OBJ_PLAYER, -1); } } else { // Not in network mode. If not fired by player, then track player. if (tracker->ctype.laser_info.parent_num != Players[Player_num].objnum) { if (!(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) best_objnum = ConsoleObject - Objects; } else { // Not in network mode and fired by player. for (i=Num_rendered_objects-1; i>=0; i--) { fix dot; //, dist; vms_vector vec_to_curobj; int objnum = Ordered_rendered_object_list[i]; object *curobjp = &Objects[objnum]; if (objnum == Players[Player_num].objnum) continue; // Can't track AI object if he's cloaked. if (curobjp->type == OBJ_ROBOT) if (curobjp->ctype.ai_info.CLOAKED) continue; vm_vec_sub(&vec_to_curobj, &curobjp->pos, curpos); vm_vec_normalize_quick(&vec_to_curobj); dot = vm_vec_dot(&vec_to_curobj, &tracker->orient.fvec); // Note: This uses the constant, not-scaled-by-frametime value, because it is only used // to determine if an object is initially trackable. find_homing_object is called on subsequent // frames to determine if the object remains trackable. if (dot > MIN_TRACKABLE_DOT) { if (dot > max_dot) { if (object_to_object_visibility(tracker, &Objects[objnum], FQ_TRANSWALL)) { max_dot = dot; best_objnum = objnum; } } } } } } return best_objnum; } // -------------------------------------------------------------------------------------------- // Find object to home in on. // Scan list of objects rendered last frame, find one that satisfies function of nearness to center and distance. // Can track two kinds of objects. If you are only interested in one type, set track_obj_type2 to NULL int find_homing_object_complete(vms_vector *curpos, object *tracker, int track_obj_type1, int track_obj_type2) { int objnum; fix max_dot = -F1_0*2; int best_objnum = -1; fix max_trackable_dist = MAX_TRACKABLE_DIST; fix min_trackable_dot = MIN_TRACKABLE_DOT; if (!Weapon_info[tracker->id].homing_flag) { Int3(); // Contact Mike: This is a bad and stupid thing. Who called this routine with an illegal laser type?? return 0; // Track the damn stupid player for causing this problem! } for (objnum=0; objnum<=Highest_object_index; objnum++) { int is_proximity = 0; fix dot, dist; vms_vector vec_to_curobj; object *curobjp = &Objects[objnum]; if ((curobjp->type != track_obj_type1) && (curobjp->type != track_obj_type2)) { if ((curobjp->type == OBJ_WEAPON) && (is_proximity_bomb_or_smart_mine(curobjp->id))) { if (curobjp->ctype.laser_info.parent_signature != tracker->ctype.laser_info.parent_signature) is_proximity = 1; else continue; } else continue; } if (objnum == tracker->ctype.laser_info.parent_num) // Don't track shooter continue; // Don't track cloaked players. if (curobjp->type == OBJ_PLAYER) { if (Players[curobjp->id].flags & PLAYER_FLAGS_CLOAKED) continue; // Don't track teammates in team games #ifdef NETWORK if ((Game_mode & GM_TEAM) && (Objects[tracker->ctype.laser_info.parent_num].type == OBJ_PLAYER) && (get_team(curobjp->id) == get_team(Objects[tracker->ctype.laser_info.parent_num].id))) continue; #endif } // Can't track AI object if he's cloaked. if (curobjp->type == OBJ_ROBOT) if (curobjp->ctype.ai_info.CLOAKED) continue; vm_vec_sub(&vec_to_curobj, &curobjp->pos, curpos); dist = vm_vec_mag(&vec_to_curobj); if (dist < max_trackable_dist) { vm_vec_normalize(&vec_to_curobj); dot = vm_vec_dot(&vec_to_curobj, &tracker->orient.fvec); if (is_proximity) dot = ((dot << 3) + dot) >> 3; // I suspect Watcom would be too stupid to figure out the obvious... // Note: This uses the constant, not-scaled-by-frametime value, because it is only used // to determine if an object is initially trackable. find_homing_object is called on subsequent // frames to determine if the object remains trackable. if (dot > min_trackable_dot) { if (dot > max_dot) { if (object_to_object_visibility(tracker, &Objects[objnum], FQ_TRANSWALL)) { max_dot = dot; best_objnum = objnum; } } } } } return best_objnum; } // ------------------------------------------------------------------------------------------------------------ // See if legal to keep tracking currently tracked object. If not, see if another object is trackable. If not, return -1, // else return object number of tracking object. int track_track_goal(int track_goal, object *tracker, fix *dot) { #ifdef NEWHOMER if (object_is_trackable(track_goal, tracker, dot) && (tracker-Objects)) { return track_goal; } else if (tracker-Objects) #else // Every 8 frames for each object, scan all objects. if (object_is_trackable(track_goal, tracker, dot) && ((((tracker-Objects) ^ d_tick_count) % 8) != 0)) { return track_goal; } else if ((((tracker-Objects) ^ d_tick_count) % 4) == 0) #endif { int rval = -2; // If player fired missile, then search for an object, if not, then give up. if (Objects[tracker->ctype.laser_info.parent_num].type == OBJ_PLAYER) { int goal_type; if (track_goal == -1) { if (Game_mode & GM_MULTI) { if (Game_mode & GM_MULTI_COOP) rval = find_homing_object_complete( &tracker->pos, tracker, OBJ_ROBOT, -1); else if (Game_mode & GM_MULTI_ROBOTS) // Not cooperative, if robots, track either robot or player rval = find_homing_object_complete( &tracker->pos, tracker, OBJ_PLAYER, OBJ_ROBOT); else // Not cooperative and no robots, track only a player rval = find_homing_object_complete( &tracker->pos, tracker, OBJ_PLAYER, -1); } else rval = find_homing_object_complete(&tracker->pos, tracker, OBJ_PLAYER, OBJ_ROBOT); } else { goal_type = Objects[tracker->ctype.laser_info.track_goal].type; if ((goal_type == OBJ_PLAYER) || (goal_type == OBJ_ROBOT)) rval = find_homing_object_complete(&tracker->pos, tracker, goal_type, -1); else rval = -1; } } else { int goal_type; if (track_goal == -1) rval = find_homing_object_complete(&tracker->pos, tracker, OBJ_PLAYER, -1); else { goal_type = Objects[tracker->ctype.laser_info.track_goal].type; rval = find_homing_object_complete(&tracker->pos, tracker, goal_type, -1); } } Assert(rval != -2); // This means it never got set which is bad! Contact Mike. return rval; } return -1; } //-------------- Initializes a laser after Fire is pressed ----------------- void Laser_player_fire_spread_delay(object *obj, int laser_type, int gun_num, fix spreadr, fix spreadu, fix delay_time, int make_sound, int harmless) { int LaserSeg, Fate; vms_vector LaserPos, LaserDir; fvi_query fq; fvi_info hit_data; vms_vector gun_point, *pnt; vms_matrix m; int objnum; // Find the initial position of the laser pnt = &Player_ship->gun_points[gun_num]; vm_copy_transpose_matrix(&m,&obj->orient); vm_vec_rotate(&gun_point,pnt,&m); vm_vec_add(&LaserPos,&obj->pos,&gun_point); // If supposed to fire at a delayed time (delay_time), then move this point backwards. if (delay_time) vm_vec_scale_add2(&LaserPos, &obj->orient.fvec, -fixmul(delay_time, Weapon_info[laser_type].speed[Difficulty_level])); // do_muzzle_stuff(obj, &Pos); //--------------- Find LaserPos and LaserSeg ------------------ fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = &LaserPos; fq.rad = 0x10; fq.thisobjnum = obj-Objects; fq.ignore_obj_list = NULL; fq.flags = FQ_CHECK_OBJS; Fate = find_vector_intersection(&fq, &hit_data); LaserSeg = hit_data.hit_seg; if (LaserSeg == -1) //some sort of annoying error return; //SORT OF HACK... IF ABOVE WAS CORRECT THIS WOULDNT BE NECESSARY. if ( vm_vec_dist_quick(&LaserPos, &obj->pos) > 0x50000 ) return; if (Fate==HIT_WALL) { return; } if (Fate==HIT_OBJECT) { // if ( Objects[hit_data.hit_object].type == OBJ_ROBOT ) // Objects[hit_data.hit_object].flags |= OF_SHOULD_BE_DEAD; // if ( Objects[hit_data.hit_object].type != OBJ_POWERUP ) // return; //as of 12/6/94, we don't care if the laser is stuck in an object. We //just fire away normally } // Now, make laser spread out. LaserDir = obj->orient.fvec; if ((spreadr != 0) || (spreadu != 0)) { vm_vec_scale_add2(&LaserDir, &obj->orient.rvec, spreadr); vm_vec_scale_add2(&LaserDir, &obj->orient.uvec, spreadu); } objnum = Laser_create_new( &LaserDir, &LaserPos, LaserSeg, obj-Objects, laser_type, make_sound ); if (objnum == -1) return; // If this weapon is supposed to be silent, set that bit! if (!make_sound) Objects[objnum].flags |= OF_SILENT; // If this weapon is supposed to be harmless, set that bit! if (harmless) Objects[objnum].flags |= OF_HARMLESS; // If the object firing the laser is the player, then indicate the laser object so robots can dodge. if (obj == ConsoleObject) Player_fired_laser_this_frame = objnum; if (Weapon_info[laser_type].homing_flag) { if (obj == ConsoleObject) { Objects[objnum].ctype.laser_info.track_goal = find_homing_object(&LaserPos, &Objects[objnum]); #ifdef NETWORK Network_laser_track = Objects[objnum].ctype.laser_info.track_goal; #endif } #ifdef NETWORK else // Some other player shot the homing thing { Assert(Game_mode & GM_MULTI); Objects[objnum].ctype.laser_info.track_goal = Network_laser_track; } #endif } } // ----------------------------------------------------------------------------------------------------------- void Laser_player_fire_spread(object *obj, int laser_type, int gun_num, fix spreadr, fix spreadu, int make_sound, int harmless) { Laser_player_fire_spread_delay(obj, laser_type, gun_num, spreadr, spreadu, 0, make_sound, harmless); } // ----------------------------------------------------------------------------------------------------------- void Laser_player_fire(object *obj, int laser_type, int gun_num, int make_sound, int harmless) { Laser_player_fire_spread(obj, laser_type, gun_num, 0, 0, make_sound, harmless); } // ----------------------------------------------------------------------------------------------------------- void Flare_create(object *obj) { fix energy_usage; energy_usage = Weapon_info[FLARE_ID].energy_usage; if (Difficulty_level < 2) energy_usage = fixmul(energy_usage, i2f(Difficulty_level+2)/4); if (Players[Player_num].energy > 0) { Players[Player_num].energy -= energy_usage; if (Players[Player_num].energy <= 0) { Players[Player_num].energy = 0; auto_select_weapon(0); } Laser_player_fire( obj, FLARE_ID, 6, 1, 0); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_fire(FLARE_ID+MISSILE_ADJUST, 0, 0, 1, -1); #endif } } #define HOMING_MISSILE_SCALE 8 //------------------------------------------------------------------------------------------- // Set object *objp's orientation to (or towards if I'm ambitious) its velocity. void homing_missile_turn_towards_velocity(object *objp, vms_vector *norm_vel) { vms_vector new_fvec; new_fvec = *norm_vel; vm_vec_scale(&new_fvec, FrameTime * HOMING_MISSILE_SCALE); vm_vec_add2(&new_fvec, &objp->orient.fvec); vm_vec_normalize_quick(&new_fvec); // if ((norm_vel->x == 0) && (norm_vel->y == 0) && (norm_vel->z == 0)) // return; vm_vector_2_matrix(&objp->orient, &new_fvec, NULL, NULL); } #ifdef NEWHOMER /* * In the original game homers turned sharper in higher FPS-values. We do not want that so we need to scale vector_to_object to FrameTime. * For each difficulty setting we have a base value the homers will align to. This we express in a FPS value representing the homers turn radius of the original game (i.e. "The homer will turn like on XXFPS"). * NOTE: Old homers only get valid track_goal every 8 frames. This does not apply anymore so these values are divided by 4 to compensate this. */ fix homing_turn_base[NDL] = { 4, 5, 6, 7, 8 }; #endif //------------------------------------------------------------------------------------------- //sequence this laser object for this _frame_ (underscores added here to aid MK in his searching!) void Laser_do_weapon_sequence(object *obj) { Assert(obj->control_type == CT_WEAPON); if (obj->lifeleft < 0 ) { // We died of old age obj->flags |= OF_SHOULD_BE_DEAD; if ( Weapon_info[obj->id].damage_radius ) explode_badass_weapon(obj); return; } //delete weapons that are not moving if ( !((d_tick_count ^ obj->signature) & 3) && (obj->id != FLARE_ID) && (Weapon_info[obj->id].speed[Difficulty_level] > 0) && (vm_vec_mag_quick(&obj->mtype.phys_info.velocity) < F2_0)) { obj_delete(obj-Objects); return; } if ( obj->id == FUSION_ID ) { //always set fusion weapon to max vel vm_vec_normalize_quick(&obj->mtype.phys_info.velocity); vm_vec_scale(&obj->mtype.phys_info.velocity, Weapon_info[obj->id].speed[Difficulty_level]); } // For homing missiles, turn towards target. if (Weapon_info[obj->id].homing_flag) { vms_vector vector_to_object, temp_vec; fix dot=F1_0; fix speed, max_speed; // For first 1/2 second of life, missile flies straight. if (obj->ctype.laser_info.creation_time + HOMING_MISSILE_STRAIGHT_TIME < GameTime64) { int track_goal = obj->ctype.laser_info.track_goal; // If it's time to do tracking, then it's time to grow up, stop bouncing and start exploding!. if ((obj->id == ROBOT_SMART_HOMING_ID) || (obj->id == PLAYER_SMART_HOMING_ID)) { obj->mtype.phys_info.flags &= ~PF_BOUNCE; } // Make sure the object we are tracking is still trackable. track_goal = track_track_goal(track_goal, obj, &dot); if (track_goal == Players[Player_num].objnum) { fix dist_to_player; dist_to_player = vm_vec_dist_quick(&obj->pos, &Objects[track_goal].pos); if ((dist_to_player < Players[Player_num].homing_object_dist) || (Players[Player_num].homing_object_dist < 0)) Players[Player_num].homing_object_dist = dist_to_player; } if (track_goal != -1) { #ifdef NEWHOMER vm_vec_sub(&vector_to_object, &Objects[track_goal].pos, &obj->pos); vm_vec_normalize_quick(&vector_to_object); temp_vec = obj->mtype.phys_info.velocity; speed = vm_vec_normalize(&temp_vec); max_speed = Weapon_info[obj->id].speed[Difficulty_level]; if (speed+F1_0 < max_speed) { speed += fixmul(max_speed, FrameTime/2); if (speed > max_speed) speed = max_speed; } // Scale vector to object to current FrameTime. vm_vec_scale(&vector_to_object, F1_0/((float)(F1_0/homing_turn_base[Difficulty_level])/FrameTime)); vm_vec_add2(&temp_vec, &vector_to_object); // The boss' smart children track better... if (Weapon_info[obj->id].render_type != WEAPON_RENDER_POLYMODEL) vm_vec_add2(&temp_vec, &vector_to_object); vm_vec_normalize(&temp_vec); vm_vec_scale(&temp_vec, speed); obj->mtype.phys_info.velocity = temp_vec; // Subtract off life proportional to amount turned. // For hardest turn, it will lose 2 seconds per second. { fix lifelost, absdot; absdot = abs(F1_0 - dot); lifelost = fixmul(absdot*32, FrameTime); obj->lifeleft -= lifelost; } // Only polygon objects have visible orientation, so only they should turn. if (Weapon_info[obj->id].render_type == WEAPON_RENDER_POLYMODEL) homing_missile_turn_towards_velocity(obj, &temp_vec); // temp_vec is normalized velocity. #else // OLD - ORIGINAL - MISSILE TRACKING CODE vm_vec_sub(&vector_to_object, &Objects[track_goal].pos, &obj->pos); vm_vec_normalize_quick(&vector_to_object); temp_vec = obj->mtype.phys_info.velocity; speed = vm_vec_normalize_quick(&temp_vec); max_speed = Weapon_info[obj->id].speed[Difficulty_level]; if (speed+F1_0 < max_speed) { speed += fixmul(max_speed, FrameTime/2); if (speed > max_speed) speed = max_speed; } dot = vm_vec_dot(&temp_vec, &vector_to_object); vm_vec_add2(&temp_vec, &vector_to_object); // The boss' smart children track better... if (Weapon_info[obj->id].render_type != WEAPON_RENDER_POLYMODEL) vm_vec_add2(&temp_vec, &vector_to_object); vm_vec_normalize_quick(&temp_vec); vm_vec_scale(&temp_vec, speed); obj->mtype.phys_info.velocity = temp_vec; // Subtract off life proportional to amount turned. // For hardest turn, it will lose 2 seconds per second. { fix lifelost, absdot; absdot = abs(F1_0 - dot); if (absdot > F1_0/8) { if (absdot > F1_0/4) absdot = F1_0/4; lifelost = fixmul(absdot*16, FrameTime); obj->lifeleft -= lifelost; } //added 8/14/98 by Victor Rachels to make homers lose life while going straight, too obj->lifeleft -= fixmul(F1_0, FrameTime); //end addition - Victor Rachels } // Only polygon objects have visible orientation, so only they should turn. if (Weapon_info[obj->id].render_type == WEAPON_RENDER_POLYMODEL) homing_missile_turn_towards_velocity(obj, &temp_vec); // temp_vec is normalized velocity. #endif } } } // Make sure weapon is not moving faster than allowed speed. if (Weapon_info[obj->id].thrust != 0) { fix weapon_speed; weapon_speed = vm_vec_mag_quick(&obj->mtype.phys_info.velocity); if (weapon_speed > Weapon_info[obj->id].speed[Difficulty_level]) { fix scale_factor; scale_factor = fixdiv(Weapon_info[obj->id].speed[Difficulty_level], weapon_speed); vm_vec_scale(&obj->mtype.phys_info.velocity, scale_factor); } } } int Spreadfire_toggle=0; fix64 Last_laser_fired_time = 0; extern int Player_fired_laser_this_frame; // -------------------------------------------------------------------------------------------------- // Assumption: This is only called by the actual console player, not for // network players int do_laser_firing_player(void) { player *plp = &Players[Player_num]; fix energy_used; int ammo_used; int weapon_index; int rval = 0; int nfires = 1; if (Player_is_dead) return 0; weapon_index = Primary_weapon_to_weapon_info[Primary_weapon]; energy_used = Weapon_info[weapon_index].energy_usage; if (Difficulty_level < 2) energy_used = fixmul(energy_used, i2f(Difficulty_level+2)/4); ammo_used = Weapon_info[weapon_index].ammo_usage; while (Next_laser_fire_time <= GameTime64) { if ((plp->energy >= energy_used) || ((Primary_weapon == VULCAN_INDEX) && (plp->primary_ammo[Primary_weapon] >= ammo_used)) ) { int laser_level, flags, fire_frame_overhead = 0; if (GameTime64 - Next_laser_fire_time <= FrameTime) // if firing is prolonged by FrameTime overhead, let's try to fix that. fire_frame_overhead = GameTime64 - Next_laser_fire_time; Last_laser_fired_time = GameTime64; if (!cheats.rapidfire) Next_laser_fire_time = GameTime64 + Weapon_info[weapon_index].fire_wait - fire_frame_overhead; else Next_laser_fire_time = GameTime64 + (F1_0/25) - fire_frame_overhead; laser_level = Players[Player_num].laser_level; flags = 0; if (Primary_weapon == SPREADFIRE_INDEX) { if (Spreadfire_toggle) flags |= LASER_SPREADFIRE_TOGGLED; Spreadfire_toggle = !Spreadfire_toggle; } if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) flags |= LASER_QUAD; rval += do_laser_firing(Players[Player_num].objnum, Primary_weapon, laser_level, flags, nfires); plp->energy -= (energy_used * rval) / Weapon_info[weapon_index].fire_count; if (plp->energy < 0) plp->energy = 0; if (ammo_used > plp->primary_ammo[Primary_weapon]) plp->primary_ammo[Primary_weapon] = 0; else plp->primary_ammo[Primary_weapon] -= ammo_used; auto_select_weapon(0); // Make sure the player can fire from this weapon. } else break; // Couldn't fire weapon, so abort. } Global_laser_firing_count = 0; return rval; } // -------------------------------------------------------------------------------------------------- // Object "objnum" fires weapon "weapon_num" of level "level". (Right now (9/24/94) level is used only for type 0 laser. // Flags are the player flags. For network mode, set to 0. // It is assumed that this is a player object (as in multiplayer), and therefore the gun positions are known. // Returns number of times a weapon was fired. This is typically 1, but might be more for low frame rates. // More than one shot is fired with a pseudo-delay so that players on slow machines can fire (for themselves // or other players) often enough for things like the vulcan cannon. int do_laser_firing(int objnum, int weapon_num, int level, int flags, int nfires) { object *objp = &Objects[objnum]; switch (weapon_num) { case LASER_INDEX: { Laser_player_fire( objp, level, 0, 1, 0); Laser_player_fire( objp, level, 1, 0, 0); if (flags & LASER_QUAD) { // hideous system to make quad laser 1.5x powerful as normal laser, make every other quad laser bolt harmless Laser_player_fire( objp, level, 2, 0, 0); Laser_player_fire( objp, level, 3, 0, 0); } break; } case VULCAN_INDEX: { // Only make sound for 1/4 of vulcan bullets. int make_sound = 1; //if (d_rand() > 24576) // make_sound = 1; Laser_player_fire_spread( objp, VULCAN_ID, 6, d_rand()/8 - 32767/16, d_rand()/8 - 32767/16, make_sound, 0); if (nfires > 1) { Laser_player_fire_spread( objp, VULCAN_ID, 6, d_rand()/8 - 32767/16, d_rand()/8 - 32767/16, 0, 0); if (nfires > 2) { Laser_player_fire_spread( objp, VULCAN_ID, 6, d_rand()/8 - 32767/16, d_rand()/8 - 32767/16, 0, 0); } } break; } case SPREADFIRE_INDEX: if (flags & LASER_SPREADFIRE_TOGGLED) { Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, F1_0/16, 0, 0, 0); Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, -F1_0/16, 0, 0, 0); Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, 0, 0, 1, 0); } else { Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, 0, F1_0/16, 0, 0); Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, 0, -F1_0/16, 0, 0); Laser_player_fire_spread( objp, SPREADFIRE_ID, 6, 0, 0, 1, 0); } break; #ifndef SHAREWARE case PLASMA_INDEX: Laser_player_fire( objp, PLASMA_ID, 0, 1, 0); Laser_player_fire( objp, PLASMA_ID, 1, 0, 0); if (nfires > 1) { Laser_player_fire_spread_delay( objp, PLASMA_ID, 0, 0, 0, FrameTime/2, 1, 0); Laser_player_fire_spread_delay( objp, PLASMA_ID, 1, 0, 0, FrameTime/2, 0, 0); } break; case FUSION_INDEX: { vms_vector force_vec; Laser_player_fire( objp, FUSION_ID, 0, 1, 0); Laser_player_fire( objp, FUSION_ID, 1, 1, 0); flags = (sbyte)(Fusion_charge >> 12); Fusion_charge = 0; force_vec.x = -(objp->orient.fvec.x << 7); force_vec.y = -(objp->orient.fvec.y << 7); force_vec.z = -(objp->orient.fvec.z << 7); phys_apply_force(objp, &force_vec); force_vec.x = (force_vec.x >> 4) + d_rand() - 16384; force_vec.y = (force_vec.y >> 4) + d_rand() - 16384; force_vec.z = (force_vec.z >> 4) + d_rand() - 16384; phys_apply_rot(objp, &force_vec); } break; #endif default: Int3(); // Contact Mike: Unknown Primary weapon type, setting to 0. Primary_weapon = 0; } // Set values to be recognized during comunication phase, if we are the // one shooting #ifdef NETWORK if ((Game_mode & GM_MULTI) && (objnum == Players[Player_num].objnum)) multi_send_fire(weapon_num, level, flags, nfires, -1); #endif return nfires; } #define MAX_SMART_DISTANCE (F1_0*150) #define MAX_OBJDISTS 30 typedef struct { int objnum; fix dist; } objdist; // ------------------------------------------------------------------------------------------- // if goal_obj == -1, then create random vector int create_homing_missile(object *objp, int goal_obj, int objtype, int make_sound) { int objnum; vms_vector vector_to_goal; vms_vector random_vector; //vms_vector goal_pos; if (goal_obj == -1) { make_random_vector(&vector_to_goal); } else { vm_vec_sub(&vector_to_goal, &Objects[goal_obj].pos, &objp->pos); vm_vec_normalize_quick(&vector_to_goal); make_random_vector(&random_vector); vm_vec_scale_add2(&vector_to_goal, &random_vector, F1_0/4); vm_vec_normalize_quick(&vector_to_goal); } // Create a vector towards the goal, then add some noise to it. objnum = Laser_create_new(&vector_to_goal, &objp->pos, objp->segnum, objp-Objects, objtype, make_sound); if (objnum == -1) return -1; // Fixed to make sure the right person gets credit for the kill // Objects[objnum].ctype.laser_info.parent_num = objp->ctype.laser_info.parent_num; // Objects[objnum].ctype.laser_info.parent_type = objp->ctype.laser_info.parent_type; // Objects[objnum].ctype.laser_info.parent_signature = objp->ctype.laser_info.parent_signature; Objects[objnum].ctype.laser_info.track_goal = goal_obj; return objnum; } // ------------------------------------------------------------------------------------------- // Create the children of a smart bomb, which is a bunch of homing missiles. void create_smart_children(object *objp, int num_smart_children) { int parent_type; int numobjs=0, objnum = 0, sel_objnum, last_sel_objnum = -1; int objlist[MAX_OBJDISTS]; int blob_id; parent_type = objp->ctype.laser_info.parent_type; if (objp->id == SMART_ID) { int i; if (Game_mode & GM_MULTI) d_srand(8321L); for (objnum=0; objnum<=Highest_object_index; objnum++) { object *curobjp = &Objects[objnum]; if ((((curobjp->type == OBJ_ROBOT) && (!curobjp->ctype.ai_info.CLOAKED)) || (curobjp->type == OBJ_PLAYER)) && (objnum != objp->ctype.laser_info.parent_num)) { fix dist; if (curobjp->type == OBJ_PLAYER) { if ((parent_type == OBJ_PLAYER) && (Game_mode & GM_MULTI_COOP)) continue; if ((Game_mode & GM_TEAM) && (get_team(curobjp->id) == get_team(Objects[objp->ctype.laser_info.parent_num].id))) continue; if (Players[curobjp->id].flags & PLAYER_FLAGS_CLOAKED) continue; } // Robot blobs can't track robots. if (curobjp->type == OBJ_ROBOT) if (parent_type == OBJ_ROBOT) continue; dist = vm_vec_dist_quick(&objp->pos, &curobjp->pos); if (dist < MAX_SMART_DISTANCE) { int oovis; oovis = object_to_object_visibility(objp, curobjp, FQ_TRANSWALL); if (oovis) { //object_to_object_visibility(objp, curobjp, FQ_TRANSWALL)) { objlist[numobjs] = objnum; numobjs++; if (numobjs >= MAX_OBJDISTS) { numobjs = MAX_OBJDISTS; break; } } } } } // Get type of weapon for child from parent. if (parent_type == OBJ_PLAYER) { blob_id = PLAYER_SMART_HOMING_ID; Assert(blob_id != -1); // Hmm, missing data in bitmaps.tbl. Need "children=NN" parameter. } else { blob_id = ((N_weapon_types> 15]; if (numobjs > 1) while (sel_objnum == last_sel_objnum) sel_objnum = objlist[(d_rand() * numobjs) >> 15]; create_homing_missile(objp, sel_objnum, blob_id, (i==0)?1:0); last_sel_objnum = sel_objnum; } } } #define CONCUSSION_GUN 4 #define HOMING_GUN 4 #define PROXIMITY_GUN 7 #define SMART_GUN 7 #define MEGA_GUN 7 int Missile_gun=0, Proximity_dropped = 0; // ------------------------------------------------------------------------------------------- //changed on 9/16/98 by adb to distinguish between drop bomb and secondary fire void do_missile_firing(int drop_bomb) { int bomb = which_bomb(); int weapon = (drop_bomb) ? bomb : Secondary_weapon; fix fire_frame_overhead = 0; Network_laser_track = -1; Assert(weapon < MAX_SECONDARY_WEAPONS); if (GameTime64 - Next_missile_fire_time <= FrameTime) // if firing is prolonged by FrameTime overhead, let's try to fix that. fire_frame_overhead = GameTime64 - Next_missile_fire_time; if (!Player_is_dead && (Players[Player_num].secondary_ammo[weapon] > 0)) { int weapon_index; Players[Player_num].secondary_ammo[weapon]--; weapon_index = Secondary_weapon_to_weapon_info[weapon]; if (!cheats.rapidfire) Next_missile_fire_time = GameTime64 + Weapon_info[weapon_index].fire_wait - fire_frame_overhead; else Next_missile_fire_time = GameTime64 + (F1_0/25) - fire_frame_overhead; switch (weapon) { case CONCUSSION_INDEX: Laser_player_fire( ConsoleObject, CONCUSSION_ID, CONCUSSION_GUN+(Missile_gun & 1), 1, 0 ); Missile_gun++; break; case PROXIMITY_INDEX: Proximity_dropped ++; if (Proximity_dropped == 4) { Proximity_dropped = 0; #ifdef NETWORK maybe_drop_net_powerup(POW_PROXIMITY_WEAPON); #endif } Laser_player_fire( ConsoleObject, PROXIMITY_ID, PROXIMITY_GUN, 1, 0); break; case HOMING_INDEX: Laser_player_fire( ConsoleObject, HOMING_ID, HOMING_GUN+(Missile_gun & 1), 1, 0 ); Missile_gun++; #ifdef NETWORK maybe_drop_net_powerup(POW_HOMING_AMMO_1); #endif break; #ifndef SHAREWARE case SMART_INDEX: Laser_player_fire( ConsoleObject, SMART_ID, SMART_GUN, 1, 0); #ifdef NETWORK maybe_drop_net_powerup(POW_SMARTBOMB_WEAPON); #endif break; case MEGA_INDEX: Laser_player_fire( ConsoleObject, MEGA_ID, MEGA_GUN, 1, 0); #ifdef NETWORK maybe_drop_net_powerup(POW_MEGA_WEAPON); #endif { vms_vector force_vec; force_vec.x = -(ConsoleObject->orient.fvec.x << 7); force_vec.y = -(ConsoleObject->orient.fvec.y << 7); force_vec.z = -(ConsoleObject->orient.fvec.z << 7); phys_apply_force(ConsoleObject, &force_vec); force_vec.x = (force_vec.x >> 4) + d_rand() - 16384; force_vec.y = (force_vec.y >> 4) + d_rand() - 16384; force_vec.z = (force_vec.z >> 4) + d_rand() - 16384; phys_apply_rot(ConsoleObject, &force_vec); } break; #endif } #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_fire(weapon+MISSILE_ADJUST, 0, (Missile_gun-1), 1, Network_laser_track); #endif // don't autoselect if dropping prox and prox not current weapon if (!drop_bomb || Secondary_weapon == PROXIMITY_INDEX) auto_select_weapon(1); //select next missile, if this one out of ammo } } #ifdef NETWORK void net_missile_firing(int player, int gun, int flags) { switch (gun-MISSILE_ADJUST) { case CONCUSSION_INDEX: Laser_player_fire( Objects+Players[player].objnum, CONCUSSION_ID, CONCUSSION_GUN+(flags & 1), 1, 0 ); break; case PROXIMITY_INDEX: Laser_player_fire( Objects+Players[player].objnum, PROXIMITY_ID, PROXIMITY_GUN, 1, 0); break; case HOMING_INDEX: Laser_player_fire( Objects+Players[player].objnum, HOMING_ID, HOMING_GUN+(flags & 1), 1, 0); break; case SMART_INDEX: Laser_player_fire( Objects+Players[player].objnum, SMART_ID, SMART_GUN, 1, 0); break; case MEGA_INDEX: Laser_player_fire( Objects+Players[player].objnum, MEGA_ID, MEGA_GUN, 1, 0); break; case FLARE_ID: Laser_player_fire( Objects+Players[player].objnum, FLARE_ID, 6, 1, 0); break; default: break; } } #endif dxx-rebirth-0.58.1-d1x/main/laser.h000066400000000000000000000114161217717257200167600ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Definitions for the laser code. * */ #ifndef _LASER_H #define _LASER_H enum weapon_type_t { CONCUSSION_ID = 8, FLARE_ID = 9, // NOTE: This MUST correspond to the ID generated at bitmaps.tbl read time. LASER_ID = 10, VULCAN_ID = 11, // NOTE: This MUST correspond to the ID generated at bitmaps.tbl read time. XSPREADFIRE_ID = 12, // NOTE: This MUST correspond to the ID generated at bitmaps.tbl read time. PLASMA_ID = 13, // NOTE: This MUST correspond to the ID generated at bitmaps.tbl read time. FUSION_ID = 14, // NOTE: This MUST correspond to the ID generated at bitmaps.tbl read time. HOMING_ID = 15, PROXIMITY_ID = 16, SMART_ID = 17, MEGA_ID = 18, PLAYER_SMART_HOMING_ID = 19, SPREADFIRE_ID = 20, SUPER_MECH_MISS = 21, REGULAR_MECH_MISS = 22, SILENT_SPREADFIRE_ID = 23, ROBOT_SMART_HOMING_ID = 29, // NOTE: check create_smart_children()!!! }; // These are new defines for the value of 'flags' passed to do_laser_firing. // The purpose is to collect other flags like QUAD_LASER and Spreadfire_toggle // into a single 8-bit quantity so it can be easily used in network mode. #define LASER_QUAD 1 #define LASER_SPREADFIRE_TOGGLED 2 #define MAX_LASER_LEVEL 3 // Note, laser levels are numbered from 0. #define MAX_LASER_BITMAPS 6 // For muzzle firing casting light. #define MUZZLE_QUEUE_MAX 8 // Constants governing homing missile behavior. // MIN_TRACKABLE_DOT gets inversely scaled by FrameTime and stuffed in Min_trackable_dot #define MIN_TRACKABLE_DOT (3*F1_0/4) #define MAX_TRACKABLE_DIST (F1_0*250) #define HOMING_MISSILE_STRAIGHT_TIME (F1_0/8) // Changed as per request of John, Adam, Yuan, but mostly John struct object; extern fix Min_trackable_dot; // MIN_TRACKABLE_DOT inversely scaled by FrameTime void Laser_render(struct object *obj); void Laser_player_fire(struct object * obj, int type, int gun_num, int make_sound, int harmless_flag); void Laser_player_fire_spread(struct object *obj, int laser_type, int gun_num, fix spreadr, fix spreadu, int make_sound, int harmless); void Laser_do_weapon_sequence(struct object *obj); void Flare_create(struct object *obj); int laser_are_related(int o1, int o2); extern int do_laser_firing_player(void); extern void do_missile_firing(int drop_bomb); extern void net_missile_firing(int player, int weapon, int flags); extern int Network_laser_track; int Laser_create_new(vms_vector * direction, vms_vector * position, int segnum, int parent, int type, int make_sound); // Fires a laser-type weapon (a Primary weapon) // Fires from object objnum, weapon type weapon_id. // Assumes that it is firing from a player object, so it knows which gun to fire from. // Returns the number of shots actually fired, which will typically be 1, but could be // higher for low frame rates when rapidfire weapons, such as vulcan or plasma are fired. extern int do_laser_firing(int objnum, int weapon_id, int level, int flags, int nfires); // Easier to call than Laser_create_new because it determines the segment containing the firing point // and deals with it being stuck in an object or through a wall. // Fires a laser of type "weapon_type" from an object (parent) in the direction "direction" from the position "position" // Returns object number of laser fired or -1 if not possible to fire laser. int Laser_create_new_easy(vms_vector * direction, vms_vector * position, int parent, int weapon_type, int make_sound); extern void create_smart_children(struct object *objp, int num_smart_children); extern int object_to_object_visibility(struct object *obj1, struct object *obj2, int trans_type); extern int Muzzle_queue_index; typedef struct muzzle_info { fix64 create_time; short segnum; vms_vector pos; } muzzle_info; extern muzzle_info Muzzle_data[MUZZLE_QUEUE_MAX]; /* * These two functions look redundant in D1X, but they are useful in * D2X. */ static inline int is_proximity_bomb_or_smart_mine(enum weapon_type_t id) { return id == PROXIMITY_ID; } static inline int is_any_proximity_mine(enum weapon_type_t id) { return id == PROXIMITY_ID; } #endif dxx-rebirth-0.58.1-d1x/main/lighting.c000066400000000000000000000431041217717257200174510ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Lighting functions. * */ #include #include // for memset() #include "fix.h" #include "vecmat.h" #include "gr.h" #include "inferno.h" #include "segment.h" #include "dxxerror.h" #include "render.h" #include "game.h" #include "vclip.h" #include "lighting.h" #include "3d.h" #include "laser.h" #include "timer.h" #include "player.h" #include "playsave.h" #include "weapon.h" #include "powerup.h" #include "fvi.h" #include "robot.h" #include "multi.h" #include "palette.h" #include "bm.h" #include "rle.h" #include "wall.h" int Do_dynamic_light=1; int use_fcd_lighting = 0; g3s_lrgb Dynamic_light[MAX_VERTICES]; #define HEADLIGHT_CONE_DOT (F1_0*9/10) #define HEADLIGHT_SCALE (F1_0*10) // ---------------------------------------------------------------------------------------------- void apply_light(g3s_lrgb obj_light_emission, int obj_seg, vms_vector *obj_pos, int n_render_vertices, int *render_vertices, int *vert_segnum_list, int objnum) { int vv; if (((obj_light_emission.r+obj_light_emission.g+obj_light_emission.b)/3) > 0) { fix obji_64 = ((obj_light_emission.r+obj_light_emission.g+obj_light_emission.b)/3)*64; // for pretty dim sources, only process vertices in object's own segment. // 12/04/95, MK, markers only cast light in own segment. if (abs(obji_64) <= F1_0*8) { int *vp = Segments[obj_seg].verts; for (vv=0; vv F1_0*32) { dist = find_connected_distance(obj_pos, obj_seg, vertpos, vsegnum, n_render_vertices, WID_RENDPAST_FLAG+WID_FLY_FLAG); if (dist >= 0) apply_light = 1; } else { dist = vm_vec_dist_quick(obj_pos, vertpos); apply_light = 1; } if (apply_light && ((dist >> headlight_shift) < abs(obji_64))) { if (dist < MIN_LIGHT_DIST) dist = MIN_LIGHT_DIST; if (headlight_shift && objnum != -1) { fix dot; vms_vector vec_to_point; vm_vec_sub(&vec_to_point, vertpos, obj_pos); vm_vec_normalize_quick(&vec_to_point); // MK, Optimization note: You compute distance about 15 lines up, this is partially redundant dot = vm_vec_dot(&vec_to_point, &Objects[objnum].orient.fvec); if (dot < F1_0/2) { // Do the normal thing, but darken around headlight. Dynamic_light[vertnum].r += fixdiv(obj_light_emission.r, fixmul(HEADLIGHT_SCALE, dist)); Dynamic_light[vertnum].g += fixdiv(obj_light_emission.g, fixmul(HEADLIGHT_SCALE, dist)); Dynamic_light[vertnum].b += fixdiv(obj_light_emission.b, fixmul(HEADLIGHT_SCALE, dist)); } else { if (Game_mode & GM_MULTI) { if (dist < max_headlight_dist) { Dynamic_light[vertnum].r += fixmul(fixmul(dot, dot), obj_light_emission.r)/8; Dynamic_light[vertnum].g += fixmul(fixmul(dot, dot), obj_light_emission.g)/8; Dynamic_light[vertnum].b += fixmul(fixmul(dot, dot), obj_light_emission.b)/8; } } else { Dynamic_light[vertnum].r += fixmul(fixmul(dot, dot), obj_light_emission.r)/8; Dynamic_light[vertnum].g += fixmul(fixmul(dot, dot), obj_light_emission.g)/8; Dynamic_light[vertnum].b += fixmul(fixmul(dot, dot), obj_light_emission.b)/8; } } } else { Dynamic_light[vertnum].r += fixdiv(obj_light_emission.r, dist); Dynamic_light[vertnum].g += fixdiv(obj_light_emission.g, dist); Dynamic_light[vertnum].b += fixdiv(obj_light_emission.b, dist); } } } } } } #define FLASH_LEN_FIXED_SECONDS (F1_0/3) #define FLASH_SCALE (3*F1_0/FLASH_LEN_FIXED_SECONDS) // ---------------------------------------------------------------------------------------------- void cast_muzzle_flash_light(int n_render_vertices, int *render_vertices, int *vert_segnum_list) { fix64 current_time; int i; short time_since_flash; current_time = timer_query(); for (i=0; itype) { case OBJ_PLAYER: { vms_vector sthrust = obj->mtype.phys_info.thrust; fix k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag)); // smooth thrust value like set_thrust_from_velocity() vm_vec_copy_scale(&sthrust,&obj->mtype.phys_info.velocity,k); light_intensity = max(vm_vec_mag_quick(&sthrust)/4, F1_0*2) + F1_0/2; break; } case OBJ_FIREBALL: if (obj->id != 0xff) { if (obj->lifeleft < F1_0*4) light_intensity = fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value); else light_intensity = Vclip[obj->id].light_value; } else light_intensity = 0; break; case OBJ_ROBOT: light_intensity = F1_0/2; // F1_0*Robot_info[obj->id].lightcast; break; case OBJ_WEAPON: { fix tval = Weapon_info[obj->id].light; if (obj->id == FLARE_ID ) light_intensity = 2* (min(tval, obj->lifeleft) + ((((fix)GameTime64) ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff)); else light_intensity = tval; break; } case OBJ_POWERUP: light_intensity = Powerup_info[obj->id].light; break; case OBJ_DEBRIS: light_intensity = F1_0/4; break; case OBJ_LIGHT: light_intensity = obj->ctype.light_info.intensity; break; default: light_intensity = 0; break; } lemission.r = lemission.g = lemission.b = light_intensity; if (!PlayerCfg.DynLightColor) // colored lights not desired so use intensity only OR no intensity (== no light == no color) at all return lemission; switch (obj->type) // find out if given object should cast colored light and compute if so { case OBJ_FIREBALL: case OBJ_WEAPON: case OBJ_FLARE: compute_color = 1; break; case OBJ_POWERUP: { switch (obj->id) { case POW_EXTRA_LIFE: case POW_ENERGY: case POW_SHIELD_BOOST: case POW_KEY_BLUE: case POW_KEY_RED: case POW_KEY_GOLD: case POW_CLOAK: case POW_INVULNERABILITY: compute_color = 1; break; default: break; } break; } } if (compute_color) { int i, t_idx_s = -1, t_idx_e = -1; if (light_intensity < F1_0) // for every effect we want color, increase light_intensity so the effect becomes barely visible light_intensity = F1_0; obj_color.r = obj_color.g = obj_color.b = 255; switch (obj->render_type) { case RT_NONE: break; // no object - no light case RT_POLYOBJ: { polymodel *po = &Polygon_models[obj->rtype.pobj_info.model_num]; if (po->n_textures <= 0) { int color = g3_poly_get_color(po->model_data); if (color) { obj_color.r = gr_current_pal[color*3]; obj_color.g = gr_current_pal[color*3+1]; obj_color.b = gr_current_pal[color*3+2]; } } else { t_idx_s = ObjBitmaps[ObjBitmapPtrs[po->first_texture]].index; t_idx_e = t_idx_s + po->n_textures - 1; } break; } case RT_LASER: { t_idx_s = t_idx_e = Weapon_info[obj->id].bitmap.index; break; } case RT_POWERUP: { t_idx_s = Vclip[obj->rtype.vclip_info.vclip_num].frames[0].index; t_idx_e = Vclip[obj->rtype.vclip_info.vclip_num].frames[Vclip[obj->rtype.vclip_info.vclip_num].num_frames-1].index; break; } case RT_WEAPON_VCLIP: { t_idx_s = Vclip[Weapon_info[obj->id].weapon_vclip].frames[0].index; t_idx_e = Vclip[Weapon_info[obj->id].weapon_vclip].frames[Vclip[Weapon_info[obj->id].weapon_vclip].num_frames-1].index; break; } default: { t_idx_s = Vclip[obj->id].frames[0].index; t_idx_e = Vclip[obj->id].frames[Vclip[obj->id].num_frames-1].index; break; } } if (t_idx_s != -1 && t_idx_e != -1) { obj_color.r = obj_color.g = obj_color.b = 0; for (i = t_idx_s; i <= t_idx_e; i++) { grs_bitmap *bm = &GameBitmaps[i]; bitmap_index bi; bi.index = i; PIGGY_PAGE_IN(bi); obj_color.r += bm->avg_color_rgb[0]; obj_color.g += bm->avg_color_rgb[1]; obj_color.b += bm->avg_color_rgb[2]; } } // obviously this object did not give us any usable color. so let's do our own but with blackjack and hookers! if (obj_color.r <= 0 && obj_color.g <= 0 && obj_color.b <= 0) obj_color.r = obj_color.g = obj_color.b = 255; // scale color to light intensity cscale = ((float)(light_intensity*3)/(obj_color.r+obj_color.g+obj_color.b)); lemission.r = obj_color.r * cscale; lemission.g = obj_color.g * cscale; lemission.b = obj_color.b * cscale; } return lemission; } // ---------------------------------------------------------------------------------------------- void set_dynamic_light(void) { int vv; int objnum; int n_render_vertices; int render_vertices[MAX_VERTICES]; int vert_segnum_list[MAX_VERTICES]; sbyte render_vertex_flags[MAX_VERTICES]; int render_seg,segnum, v; static fix light_time; Num_headlights = 0; if (!Do_dynamic_light) return; light_time += FrameTime; if (light_time < (F1_0/60)) // it's enough to stress the CPU 60 times per second return; light_time = light_time - (F1_0/60); memset(render_vertex_flags, 0, Highest_vertex_index+1); // Create list of vertices that need to be looked at for setting of ambient light. n_render_vertices = 0; for (render_seg=0; render_segHighest_vertex_index) { Int3(); //invalid vertex number continue; //ignore it, and go on to next one } if (!render_vertex_flags[vnum]) { render_vertex_flags[vnum] = 1; render_vertices[n_render_vertices] = vnum; vert_segnum_list[n_render_vertices] = segnum; n_render_vertices++; } } } } for (vv=0; vv= 0 && vertnum <= Highest_vertex_index); Dynamic_light[vertnum].r = Dynamic_light[vertnum].g = Dynamic_light[vertnum].b = 0; } cast_muzzle_flash_light(n_render_vertices, render_vertices, vert_segnum_list); for (objnum=0; objnum<=Highest_object_index; objnum++) { object *obj = &Objects[objnum]; vms_vector *objpos = &obj->pos; g3s_lrgb obj_light_emission; obj_light_emission = compute_light_emission(objnum); if (((obj_light_emission.r+obj_light_emission.g+obj_light_emission.b)/3) > 0) apply_light(obj_light_emission, obj->segnum, objpos, n_render_vertices, render_vertices, vert_segnum_list, objnum); } } // --------------------------------------------------------- #define HEADLIGHT_BOOST_SCALE 8 //how much to scale light when have headlight boost fix Beam_brightness = (F1_0/2); //global saying how bright the light beam is #define MAX_DIST_LOG 6 //log(MAX_DIST-expressed-as-integer) #define MAX_DIST (f1_0<type != OBJ_ROBOT) && (objp->type != OBJ_PLAYER)) return 0; light = 0; for (i=0; ipos, &light_objp->pos); dist = vm_vec_normalize_quick(&vec_to_obj); if (dist > 0) { dot = vm_vec_dot(&light_objp->orient.fvec, &vec_to_obj); if (dot < F1_0/2) light += fixdiv(HEADLIGHT_SCALE, fixmul(HEADLIGHT_SCALE, dist)); // Do the normal thing, but darken around headlight. else light += fixmul(fixmul(dot, dot), HEADLIGHT_SCALE)/8; } } return light; } //compute the average dynamic light in a segment. Takes the segment number g3s_lrgb compute_seg_dynamic_light(int segnum) { g3s_lrgb sum, seg_lrgb; segment *seg; int *verts; seg = &Segments[segnum]; verts = seg->verts; sum.r = sum.g = sum.b = 0; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts++].b; sum.r += Dynamic_light[*verts].r; sum.g += Dynamic_light[*verts].g; sum.b += Dynamic_light[*verts].b; seg_lrgb.r = sum.r >> 3; seg_lrgb.g = sum.g >> 3; seg_lrgb.b = sum.b >> 3; return seg_lrgb; } g3s_lrgb object_light[MAX_OBJECTS]; int object_sig[MAX_OBJECTS]; object *old_viewer; int reset_lighting_hack; #define LIGHT_RATE i2f(4) //how fast the light ramps up void start_lighting_frame(object *viewer) { reset_lighting_hack = (viewer != old_viewer); old_viewer = viewer; } //compute the lighting for an object. Takes a pointer to the object, //and possibly a rotated 3d point. If the point isn't specified, the //object's center point is rotated. g3s_lrgb compute_object_light(object *obj,vms_vector *rotated_pnt) { g3s_lrgb light, seg_dl; fix mlight; g3s_point objpnt; int objnum = obj-Objects; if (!rotated_pnt) { g3_rotate_point(&objpnt,&obj->pos); rotated_pnt = &objpnt.p3_vec; } //First, get static (mono) light for this segment light.r = light.g = light.b = Segments[obj->segnum].static_light; //Now, maybe return different value to smooth transitions if (!reset_lighting_hack && object_sig[objnum] == obj->signature) { fix frame_delta; g3s_lrgb delta_light; delta_light.r = light.r - object_light[objnum].r; delta_light.g = light.g - object_light[objnum].g; delta_light.b = light.b - object_light[objnum].b; frame_delta = fixmul(LIGHT_RATE,FrameTime); if (abs(((delta_light.r+delta_light.g+delta_light.b)/3)) <= frame_delta) { object_light[objnum] = light; //we've hit the goal } else { if (((delta_light.r+delta_light.g+delta_light.b)/3) < 0) { light.r = object_light[objnum].r -= frame_delta; light.g = object_light[objnum].g -= frame_delta; light.b = object_light[objnum].b -= frame_delta; } else { light.r = object_light[objnum].r += frame_delta; light.g = object_light[objnum].g += frame_delta; light.b = object_light[objnum].b += frame_delta; } } } else //new object, initialize { object_sig[objnum] = obj->signature; object_light[objnum].r = light.r; object_light[objnum].g = light.g; object_light[objnum].b = light.b; } //Next, add in (NOTE: WHITE) headlight on this object mlight = compute_headlight_light_on_object(obj); light.r += mlight; light.g += mlight; light.b += mlight; //Finally, add in dynamic light for this segment seg_dl = compute_seg_dynamic_light(obj->segnum); light.r += seg_dl.r; light.g += seg_dl.g; light.b += seg_dl.b; return light; } dxx-rebirth-0.58.1-d1x/main/lighting.h000066400000000000000000000034471217717257200174640ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Lighting system prototypes, structures, etc. * */ #ifndef _LIGHTING_H #define _LIGHTING_H #define MAX_LIGHT 0x10000 // max value #define MIN_LIGHT_DIST (F1_0*4) extern fix Beam_brightness; extern g3s_lrgb Dynamic_light[MAX_VERTICES]; extern void set_dynamic_light(void); // Compute the lighting from the headlight for a given vertex on a face. // Takes: // point - the 3d coords of the point // face_light - a scale factor derived from the surface normal of the face // If no surface normal effect is wanted, pass F1_0 for face_light fix compute_headlight_light(vms_vector *point,fix face_light); // compute the average dynamic light in a segment. Takes the segment number g3s_lrgb compute_seg_dynamic_light(int segnum); // compute the lighting for an object. Takes a pointer to the object, // and possibly a rotated 3d point. If the point isn't specified, the // object's center point is rotated. g3s_lrgb compute_object_light(object *obj,vms_vector *rotated_pnt); // turn headlight boost on & off void toggle_headlight_active(void); #endif /* _LIGHTING_H */ dxx-rebirth-0.58.1-d1x/main/menu.c000066400000000000000000002017511217717257200166140ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Inferno main menu. * */ #include #include #include "menu.h" #include "inferno.h" #include "game.h" #include "gr.h" #include "key.h" #include "mouse.h" #include "iff.h" #include "u_mem.h" #include "dxxerror.h" #include "bm.h" #include "screens.h" #include "joy.h" #include "vecmat.h" #include "effects.h" #include "slew.h" #include "gamemine.h" #include "gamesave.h" #include "palette.h" #include "args.h" #include "newdemo.h" #include "timer.h" #include "sounds.h" #include "gameseq.h" #include "text.h" #include "gamefont.h" #include "newmenu.h" #include "scores.h" #include "playsave.h" #include "kconfig.h" #include "titles.h" #include "credits.h" #include "texmap.h" #include "polyobj.h" #include "state.h" #include "mission.h" #include "songs.h" #ifdef USE_SDLMIXER #include "jukebox.h" // for jukebox_exts #endif #include "config.h" #include "gauges.h" #include "hudmsg.h" //for HUD_max_num_disp #include "strutil.h" #include "multi.h" #include "vers_id.h" #ifdef USE_UDP #include "net_udp.h" #endif #ifdef EDITOR #include "editor/editor.h" #include "editor/kdefs.h" #endif #ifdef OGL #include "ogl_init.h" #endif // Menu IDs... enum MENUS { MENU_NEW_GAME = 0, MENU_GAME, MENU_EDITOR, MENU_VIEW_SCORES, MENU_QUIT, MENU_LOAD_GAME, MENU_SAVE_GAME, MENU_DEMO_PLAY, MENU_CONFIG, MENU_REJOIN_NETGAME, MENU_DIFFICULTY, MENU_HELP, MENU_NEW_PLAYER, #if defined(USE_UDP) MENU_MULTIPLAYER, #endif MENU_SHOW_CREDITS, MENU_ORDER_INFO, #ifdef USE_UDP MENU_START_UDP_NETGAME, MENU_JOIN_MANUAL_UDP_NETGAME, MENU_JOIN_LIST_UDP_NETGAME, #endif #ifndef RELEASE MENU_SANDBOX #endif }; //ADD_ITEM("Start netgame...", MENU_START_NETGAME, -1 ); //ADD_ITEM("Send net message...", MENU_SEND_NET_MESSAGE, -1 ); #define ADD_ITEM(t,value,key) do { m[num_options].type=NM_TYPE_MENU; m[num_options].text=t; menu_choice[num_options]=value;num_options++; } while (0) static window *menus[16] = { NULL }; // Function Prototypes added after LINTING int do_option(int select); int do_new_game_menu(void); void do_multi_player_menu(); #ifndef RELEASE void do_sandbox_menu(); #endif extern void newmenu_free_background(); extern void ReorderPrimary(); extern void ReorderSecondary(); // Hide all menus int hide_menus(void) { window *wind; int i; if (menus[0]) return 0; // there are already hidden menus for (i = 0; (i < 15) && (wind = window_get_front()); i++) { menus[i] = wind; window_set_visible(wind, 0); } Assert(window_get_front() == NULL); menus[i] = NULL; return 1; } // Show all menus, with the front one shown first // This makes sure EVENT_WINDOW_ACTIVATED is only sent to that window void show_menus(void) { int i; for (i = 0; (i < 16) && menus[i]; i++) if (window_exists(menus[i])) window_set_visible(menus[i], 1); menus[0] = NULL; } //pairs of chars describing ranges char playername_allowed_chars[] = "azAZ09__--"; int MakeNewPlayerFile(int allow_abort) { int x; char filename[PATH_MAX]; newmenu_item m; char text[CALLSIGN_LEN+9]=""; strncpy(text, Players[Player_num].callsign,CALLSIGN_LEN); try_again: m.type=NM_TYPE_INPUT; m.text_len = CALLSIGN_LEN; m.text = text; Newmenu_allowed_chars = playername_allowed_chars; x = newmenu_do( NULL, TXT_ENTER_PILOT_NAME, 1, &m, NULL, NULL ); Newmenu_allowed_chars = NULL; if ( x < 0 ) { if ( allow_abort ) return 0; goto try_again; } if (text[0]==0) //null string goto try_again; d_strlwr(text); memset(filename, '\0', PATH_MAX); snprintf( filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%s.plr" : "%s.plr", text ); if (PHYSFSX_exists(filename,0)) { nm_messagebox(NULL, 1, TXT_OK, "%s '%s' %s", TXT_PLAYER, text, TXT_ALREADY_EXISTS ); goto try_again; } if ( !new_player_config() ) goto try_again; // They hit Esc during New player config strncpy(Players[Player_num].callsign, text, CALLSIGN_LEN); d_strlwr(Players[Player_num].callsign); write_player_file(); return 1; } void delete_player_saved_games(char * name); int player_menu_keycommand( listbox *lb, d_event *event ) { char **items = listbox_get_items(lb); int citem = listbox_get_citem(lb); switch (event_key_get(event)) { case KEY_CTRLED+KEY_D: if (citem > 0) { int x = 1; x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_PILOT, items[citem]+((items[citem][0]=='$')?1:0) ); if (x==0) { char * p; char plxfile[PATH_MAX], efffile[PATH_MAX], ngpfile[PATH_MAX]; int ret; char name[PATH_MAX]; p = items[citem] + strlen(items[citem]); *p = '.'; strcpy(name, GameArg.SysUsePlayersDir ? "Players/" : ""); strcat(name, items[citem]); ret = !PHYSFS_delete(name); *p = 0; if (!ret) { delete_player_saved_games( items[citem] ); // delete PLX file sprintf(plxfile, GameArg.SysUsePlayersDir? "Players/%.8s.plx" : "%.8s.plx", items[citem]); if (PHYSFSX_exists(plxfile,0)) PHYSFS_delete(plxfile); // delete EFF file sprintf(efffile, GameArg.SysUsePlayersDir? "Players/%.8s.eff" : "%.8s.eff", items[citem]); if (PHYSFSX_exists(efffile,0)) PHYSFS_delete(efffile); // delete NGP file sprintf(ngpfile, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", items[citem]); if (PHYSFSX_exists(ngpfile,0)) PHYSFS_delete(ngpfile); } if (ret) nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_PILOT, items[citem]+((items[citem][0]=='$')?1:0) ); else listbox_delete_item(lb, citem); } return 1; } break; } return 0; } int player_menu_handler( listbox *lb, d_event *event, char **list ) { char **items = listbox_get_items(lb); int citem = listbox_get_citem(lb); switch (event->type) { case EVENT_KEY_COMMAND: return player_menu_keycommand(lb, event); break; case EVENT_NEWMENU_SELECTED: if (citem < 0) return 0; // shouldn't happen else if (citem == 0) { // They selected 'create new pilot' return !MakeNewPlayerFile(1); } else { strncpy(Players[Player_num].callsign,items[citem] + ((items[citem][0]=='$')?1:0), CALLSIGN_LEN); d_strlwr(Players[Player_num].callsign); } break; case EVENT_WINDOW_CLOSE: if (read_player_file() != EZERO) return 1; // abort close! WriteConfigFile(); // Update lastplr PHYSFS_freeList(list); d_free(items); break; default: break; } return 0; } //Inputs the player's name, without putting up the background screen int RegisterPlayer() { char **m; char **f; char **list; static const char *const types[] = { ".plr", NULL }; int i = 0, NumItems; int citem = 0; int allow_abort_flag = 1; if ( Players[Player_num].callsign[0] == 0 ) { if (GameCfg.LastPlayer[0]==0) { strncpy( Players[Player_num].callsign, "player", CALLSIGN_LEN ); allow_abort_flag = 0; } else { // Read the last player's name from config file, not lastplr.txt strncpy( Players[Player_num].callsign, GameCfg.LastPlayer, CALLSIGN_LEN ); } } list = PHYSFSX_findFiles(GameArg.SysUsePlayersDir ? "Players/" : "", types); if (!list) return 0; // memory error if (!*list) { MakeNewPlayerFile(0); // make a new player without showing listbox PHYSFS_freeList(list); return 0; } for (NumItems = 0; list[NumItems] != NULL; NumItems++) {} NumItems++; // for TXT_CREATE_NEW MALLOC(m, char *, NumItems); if (m == NULL) { PHYSFS_freeList(list); return 0; } m[i++] = TXT_CREATE_NEW; for (f = list; *f != NULL; f++) { char *p; if (strlen(*f) > FILENAME_LEN-1 || strlen(*f) < 5) // sorry guys, can only have up to eight chars for the player name { NumItems--; continue; } m[i++] = *f; p = strchr(*f, '.'); if (p) *p = '\0'; // chop the .plr } if (NumItems <= 1) // so it seems all plr files we found were too long. funny. let's make a real player { MakeNewPlayerFile(0); // make a new player without showing listbox PHYSFS_freeList(list); return 0; } // Sort by name, except the string qsort(&m[1], NumItems - 1, sizeof(char *), (int (*)( const void *, const void * ))string_array_sort_func); for ( i=0; itype) { case EVENT_WINDOW_ACTIVATED: if ( Players[Player_num].callsign[0]==0 ) RegisterPlayer(); else keyd_time_when_last_pressed = timer_query(); // .. 20 seconds from now! break; case EVENT_KEY_COMMAND: // Don't allow them to hit ESC in the main menu. if (event_key_get(event)==KEY_ESC) return 1; break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: // Don't allow mousebutton-closing in main menu. if (event_mouse_get_button(event) == MBTN_RIGHT) return 1; break; case EVENT_IDLE: if ( keyd_time_when_last_pressed+i2f(45) < timer_query() || GameArg.SysAutoDemo ) { keyd_time_when_last_pressed = timer_query(); // Reset timer so that disk won't thrash if no demos. newdemo_start_playback(NULL); // Randomly pick a file } break; case EVENT_NEWMENU_DRAW: draw_copyright(); break; case EVENT_NEWMENU_SELECTED: return do_option(menu_choice[newmenu_get_citem(menu)]); break; case EVENT_WINDOW_CLOSE: d_free(menu_choice); d_free(items); break; default: break; } return 0; } // ----------------------------------------------------------------------------- // Create the main menu. void create_main_menu(newmenu_item *m, int *menu_choice, int *callers_num_options) { int num_options; #ifndef DEMO_ONLY num_options = 0; ADD_ITEM(TXT_NEW_GAME,MENU_NEW_GAME,KEY_N); ADD_ITEM(TXT_LOAD_GAME,MENU_LOAD_GAME,KEY_L); #if defined(USE_UDP) ADD_ITEM(TXT_MULTIPLAYER_,MENU_MULTIPLAYER,-1); #endif ADD_ITEM(TXT_OPTIONS_, MENU_CONFIG, -1 ); ADD_ITEM(TXT_CHANGE_PILOTS,MENU_NEW_PLAYER,unused); ADD_ITEM(TXT_VIEW_DEMO,MENU_DEMO_PLAY,0); ADD_ITEM(TXT_VIEW_SCORES,MENU_VIEW_SCORES,KEY_V); if (!PHYSFSX_exists("warning.pcx",1)) /* SHAREWARE */ ADD_ITEM(TXT_ORDERING_INFO,MENU_ORDER_INFO,-1); ADD_ITEM(TXT_CREDITS,MENU_SHOW_CREDITS,-1); #endif ADD_ITEM(TXT_QUIT,MENU_QUIT,KEY_Q); #ifndef RELEASE if (!(Game_mode & GM_MULTI )) { //m[num_options].type=NM_TYPE_TEXT; //m[num_options++].text=" Debug options:"; #ifdef EDITOR ADD_ITEM(" Editor", MENU_EDITOR, KEY_E); #endif } ADD_ITEM(" SANDBOX", MENU_SANDBOX, -1); #endif *callers_num_options = num_options; } //returns number of item chosen int DoMenu() { int *menu_choice; newmenu_item *m; int num_options = 0; MALLOC(menu_choice, int, 25); if (!menu_choice) return -1; MALLOC(m, newmenu_item, 25); if (!m) { d_free(menu_choice); return -1; } memset(menu_choice, 0, sizeof(int)*25); memset(m, 0, sizeof(newmenu_item)*25); create_main_menu(m, menu_choice, &num_options); // may have to change, eg, maybe selected pilot and no save games. newmenu_do3( "", NULL, num_options, m, (int (*)(newmenu *, d_event *, void *))main_menu_handler, menu_choice, 0, Menu_pcx_name); return 0; } extern void show_order_form(void); // John didn't want this in inferno.h so I just externed it. //returns flag, true means quit menu int do_option ( int select) { switch (select) { case MENU_NEW_GAME: select_mission(0, "New Game\n\nSelect mission", do_new_game_menu); break; case MENU_GAME: break; case MENU_DEMO_PLAY: select_demo(); break; case MENU_LOAD_GAME: state_restore_all(0); break; #ifdef EDITOR case MENU_EDITOR: if (!Current_mission) { create_new_mine(); SetPlayerFromCurseg(); } hide_menus(); init_editor(); break; #endif case MENU_VIEW_SCORES: scores_view(NULL, -1); break; #if 1 //def SHAREWARE case MENU_ORDER_INFO: show_order_form(); break; #endif case MENU_QUIT: #ifdef EDITOR if (! SafetyCheck()) break; #endif return 0; case MENU_NEW_PLAYER: RegisterPlayer(); break; #ifdef USE_UDP case MENU_START_UDP_NETGAME: multi_protocol = MULTI_PROTO_UDP; select_mission(1, TXT_MULTI_MISSION, net_udp_setup_game); break; case MENU_JOIN_MANUAL_UDP_NETGAME: multi_protocol = MULTI_PROTO_UDP; net_udp_manual_join_game(); break; case MENU_JOIN_LIST_UDP_NETGAME: multi_protocol = MULTI_PROTO_UDP; net_udp_list_join_game(); break; #endif #if defined(USE_UDP) case MENU_MULTIPLAYER: do_multi_player_menu(); break; #endif case MENU_CONFIG: do_options_menu(); break; case MENU_SHOW_CREDITS: credits_show(NULL); break; #ifndef RELEASE case MENU_SANDBOX: do_sandbox_menu(); break; #endif default: Error("Unknown option %d in do_option",select); break; } return 1; // stay in main menu unless quitting } void delete_player_saved_games(char * name) { int i; char filename[PATH_MAX]; for (i=0;i<10; i++) { snprintf( filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%s.sg%x" : "%s.sg%x", name, i ); PHYSFS_delete(filename); snprintf( filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%s.mg%x" : "%s.mg%x", name, i ); PHYSFS_delete(filename); } } int demo_menu_keycommand( listbox *lb, d_event *event ) { char **items = listbox_get_items(lb); int citem = listbox_get_citem(lb); switch (event_key_get(event)) { case KEY_CTRLED+KEY_D: if (citem >= 0) { int x = 1; x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_DEMO, items[citem]+((items[citem][0]=='$')?1:0) ); if (x==0) { int ret; char name[PATH_MAX]; strcpy(name, DEMO_DIR); strcat(name,items[citem]); ret = !PHYSFS_delete(name); if (ret) nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_DEMO, items[citem]+((items[citem][0]=='$')?1:0) ); else listbox_delete_item(lb, citem); } return 1; } break; case KEY_CTRLED+KEY_C: { int x = 1; char bakname[PATH_MAX]; // Get backup name change_filename_extension(bakname, items[citem]+((items[citem][0]=='$')?1:0), DEMO_BACKUP_EXT); x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "Are you sure you want to\n" "swap the endianness of\n" "%s? If the file is\n" "already endian native, D1X\n" "will likely crash. A backup\n" "%s will be created", items[citem]+((items[citem][0]=='$')?1:0), bakname ); if (!x) newdemo_swap_endian(items[citem]); return 1; } break; } return 0; } int demo_menu_handler( listbox *lb, d_event *event, void *userdata ) { char **items = listbox_get_items(lb); int citem = listbox_get_citem(lb); userdata = userdata; switch (event->type) { case EVENT_KEY_COMMAND: return demo_menu_keycommand(lb, event); break; case EVENT_NEWMENU_SELECTED: if (citem < 0) return 0; // shouldn't happen newdemo_start_playback(items[citem]); return 1; // stay in demo selector case EVENT_WINDOW_CLOSE: PHYSFS_freeList(items); break; default: break; } return 0; } int select_demo(void) { char **list; static const char *const types[] = { DEMO_EXT, NULL }; int NumItems; list = PHYSFSX_findFiles(DEMO_DIR, types); if (!list) return 0; // memory error if ( !*list ) { nm_messagebox( NULL, 1, TXT_OK, "%s %s\n%s", TXT_NO_DEMO_FILES, TXT_USE_F5, TXT_TO_CREATE_ONE); PHYSFS_freeList(list); return 0; } for (NumItems = 0; list[NumItems] != NULL; NumItems++) {} // Sort by name qsort(list, NumItems, sizeof(char *), (int (*)( const void *, const void * ))string_array_sort_func); newmenu_listbox1(TXT_SELECT_DEMO, NumItems, list, 1, 0, demo_menu_handler, NULL); return 1; } int do_difficulty_menu() { int s; newmenu_item m[5]; m[0].type=NM_TYPE_MENU; m[0].text=MENU_DIFFICULTY_TEXT(0); m[1].type=NM_TYPE_MENU; m[1].text=MENU_DIFFICULTY_TEXT(1); m[2].type=NM_TYPE_MENU; m[2].text=MENU_DIFFICULTY_TEXT(2); m[3].type=NM_TYPE_MENU; m[3].text=MENU_DIFFICULTY_TEXT(3); m[4].type=NM_TYPE_MENU; m[4].text=MENU_DIFFICULTY_TEXT(4); s = newmenu_do1( NULL, TXT_DIFFICULTY_LEVEL, NDL, m, NULL, NULL, Difficulty_level); if (s > -1 ) { if (s != Difficulty_level) { PlayerCfg.DefaultDifficulty = s; write_player_file(); } Difficulty_level = s; return 1; } return 0; } int do_new_game_menu() { int new_level_num,player_highest_level; new_level_num = 1; #ifdef NDEBUG player_highest_level = get_highest_level(); if (player_highest_level > Last_level) #endif player_highest_level = Last_level; if (player_highest_level > 1) { newmenu_item m[4]; char info_text[80]; char num_text[10]; int choice; int n_items; int valid = 0; while (!valid) { sprintf(info_text,"%s %d",TXT_START_ANY_LEVEL, player_highest_level); m[0].type=NM_TYPE_TEXT; m[0].text = info_text; m[1].type=NM_TYPE_INPUT; m[1].text_len = 10; m[1].text = num_text; n_items = 2; strcpy(num_text,"1"); choice = newmenu_do( NULL, TXT_SELECT_START_LEV, n_items, m, NULL, NULL ); if (choice==-1 || m[1].text[0]==0) return 0; new_level_num = atoi(m[1].text); if (!(new_level_num>0 && new_level_num<=player_highest_level)) { m[0].text = TXT_ENTER_TO_CONT; nm_messagebox( NULL, 1, TXT_OK, TXT_INVALID_LEVEL); valid = 0; } else valid = 1; } } Difficulty_level = PlayerCfg.DefaultDifficulty; if (!do_difficulty_menu()) return 0; StartNewGame(new_level_num); return 1; // exit mission listbox } void do_sound_menu(); void input_config(); void change_res(); void graphics_config(); void do_misc_menu(); int options_menuset(newmenu *menu, d_event *event, void *userdata) { switch (event->type) { case EVENT_NEWMENU_CHANGED: break; case EVENT_NEWMENU_SELECTED: switch(newmenu_get_citem(menu)) { case 0: do_sound_menu(); break; case 2: input_config(); break; case 4: change_res(); break; case 5: graphics_config(); break; case 7: ReorderPrimary(); break; case 8: ReorderSecondary(); break; case 9: do_misc_menu(); break; } return 1; // stay in menu until escape break; case EVENT_WINDOW_CLOSE: { newmenu_item *items = newmenu_get_items(menu); d_free(items); write_player_file(); break; } default: break; } userdata = userdata; //kill warning return 0; } int gcd(int a, int b) { if (!b) return a; return gcd(b, a%b); } void change_res() { u_int32_t modes[50], new_mode = 0; int i = 0, mc = 0, num_presets = 0, citem = -1, opt_cval = -1, opt_fullscr = -1; num_presets = gr_list_modes( modes ); { newmenu_item m[50+8]; char restext[50][12], crestext[12], casptext[12]; for (i = 0; i <= num_presets-1; i++) { snprintf(restext[mc], sizeof(restext[mc]), "%ix%i", SM_W(modes[i]), SM_H(modes[i])); m[mc].type = NM_TYPE_RADIO; m[mc].text = restext[mc]; m[mc].value = ((citem == -1) && (Game_screen_mode == modes[i]) && GameCfg.AspectY == SM_W(modes[i])/gcd(SM_W(modes[i]),SM_H(modes[i])) && GameCfg.AspectX == SM_H(modes[i])/gcd(SM_W(modes[i]),SM_H(modes[i]))); m[mc].group = 0; if (m[mc].value) citem = mc; mc++; } m[mc].type = NM_TYPE_TEXT; m[mc].text = ""; mc++; // little space for overview // the fields for custom resolution and aspect opt_cval = mc; m[mc].type = NM_TYPE_RADIO; m[mc].text = "use custom values"; m[mc].value = (citem == -1); m[mc].group = 0; mc++; m[mc].type = NM_TYPE_TEXT; m[mc].text = "resolution:"; mc++; snprintf(crestext, sizeof(crestext), "%ix%i", SM_W(Game_screen_mode), SM_H(Game_screen_mode)); m[mc].type = NM_TYPE_INPUT; m[mc].text = crestext; m[mc].text_len = 11; modes[mc] = 0; mc++; m[mc].type = NM_TYPE_TEXT; m[mc].text = "aspect:"; mc++; snprintf(casptext, sizeof(casptext), "%ix%i", GameCfg.AspectY, GameCfg.AspectX); m[mc].type = NM_TYPE_INPUT; m[mc].text = casptext; m[mc].text_len = 11; modes[mc] = 0; mc++; m[mc].type = NM_TYPE_TEXT; m[mc].text = ""; mc++; // little space for overview // fullscreen opt_fullscr = mc; m[mc].type = NM_TYPE_CHECK; m[mc].text = "Fullscreen"; m[mc].value = gr_check_fullscreen(); mc++; // create the menu newmenu_do1(NULL, "Screen Resolution", mc, m, NULL, NULL, 0); // menu is done, now do what we need to do // check which resolution field was selected for (i = 0; i <= mc; i++) if ((m[i].type == NM_TYPE_RADIO) && (m[i].group==0) && (m[i].value == 1)) break; // now check for fullscreen toggle and apply if necessary if (m[opt_fullscr].value != gr_check_fullscreen()) gr_toggle_fullscreen(); if (i == opt_cval) // set custom resolution and aspect { u_int32_t cmode = Game_screen_mode, casp = Game_screen_mode; if (!strchr(crestext, 'x')) return; cmode = SM(atoi(crestext), atoi(strchr(crestext, 'x')+1)); if (SM_W(cmode) < 320 || SM_H(cmode) < 200) // oh oh - the resolution is too small. Revert! { nm_messagebox( TXT_WARNING, 1, "OK", "Entered resolution is too small.\nReverting ..." ); cmode = new_mode; } casp = cmode; if (strchr(casptext, 'x')) // we even have a custom aspect set up { casp = SM(atoi(casptext), atoi(strchr(casptext, 'x')+1)); } GameCfg.AspectY = SM_W(casp)/gcd(SM_W(casp),SM_H(casp)); GameCfg.AspectX = SM_H(casp)/gcd(SM_W(casp),SM_H(casp)); new_mode = cmode; } else if (i >= 0 && i < num_presets) // set preset resolution { new_mode = modes[i]; GameCfg.AspectY = SM_W(new_mode)/gcd(SM_W(new_mode),SM_H(new_mode)); GameCfg.AspectX = SM_H(new_mode)/gcd(SM_W(new_mode),SM_H(new_mode)); } // clean up and apply everything newmenu_free_background(); set_screen_mode(SCREEN_MENU); if (new_mode != Game_screen_mode) { gr_set_mode(new_mode); Game_screen_mode = new_mode; if (Game_wind) // shortly activate Game_wind so it's canvas will align to new resolution. really minor glitch but whatever { d_event event; WINDOW_SEND_EVENT(Game_wind, EVENT_WINDOW_ACTIVATED); WINDOW_SEND_EVENT(Game_wind, EVENT_WINDOW_DEACTIVATED); } } game_init_render_buffers(SM_W(Game_screen_mode), SM_H(Game_screen_mode)); } } void input_config_sensitivity() { newmenu_item m[33]; int i = 0, nitems = 0, keysens = 0, joysens = 0, joydead = 0, mousesens = 0, mousefsdead; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Keyboard Sensitivity:"; nitems++; keysens = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_TURN_LR; m[nitems].value = PlayerCfg.KeyboardSens[0]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_PITCH_UD; m[nitems].value = PlayerCfg.KeyboardSens[1]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_LR; m[nitems].value = PlayerCfg.KeyboardSens[2]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_UD; m[nitems].value = PlayerCfg.KeyboardSens[3]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_BANK_LR; m[nitems].value = PlayerCfg.KeyboardSens[4]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Joystick Sensitivity:"; nitems++; joysens = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_TURN_LR; m[nitems].value = PlayerCfg.JoystickSens[0]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_PITCH_UD; m[nitems].value = PlayerCfg.JoystickSens[1]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_LR; m[nitems].value = PlayerCfg.JoystickSens[2]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_UD; m[nitems].value = PlayerCfg.JoystickSens[3]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_BANK_LR; m[nitems].value = PlayerCfg.JoystickSens[4]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_THROTTLE; m[nitems].value = PlayerCfg.JoystickSens[5]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Joystick Deadzone:"; nitems++; joydead = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_TURN_LR; m[nitems].value = PlayerCfg.JoystickDead[0]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_PITCH_UD; m[nitems].value = PlayerCfg.JoystickDead[1]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_LR; m[nitems].value = PlayerCfg.JoystickDead[2]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_UD; m[nitems].value = PlayerCfg.JoystickDead[3]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_BANK_LR; m[nitems].value = PlayerCfg.JoystickDead[4]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_THROTTLE; m[nitems].value = PlayerCfg.JoystickDead[5]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Mouse Sensitivity:"; nitems++; mousesens = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_TURN_LR; m[nitems].value = PlayerCfg.MouseSens[0]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_PITCH_UD; m[nitems].value = PlayerCfg.MouseSens[1]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_LR; m[nitems].value = PlayerCfg.MouseSens[2]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_SLIDE_UD; m[nitems].value = PlayerCfg.MouseSens[3]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_BANK_LR; m[nitems].value = PlayerCfg.MouseSens[4]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_THROTTLE; m[nitems].value = PlayerCfg.MouseSens[5]; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Mouse FlightSim Deadzone:"; nitems++; mousefsdead = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "X/Y"; m[nitems].value = PlayerCfg.MouseFSDead; m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; newmenu_do1(NULL, "SENSITIVITY & DEADZONE", nitems, m, NULL, NULL, 1); for (i = 0; i <= 5; i++) { if (i < 5) PlayerCfg.KeyboardSens[i] = m[keysens+i].value; PlayerCfg.JoystickSens[i] = m[joysens+i].value; PlayerCfg.JoystickDead[i] = m[joydead+i].value; PlayerCfg.MouseSens[i] = m[mousesens+i].value; } PlayerCfg.MouseFSDead = m[mousefsdead].value; } static int opt_ic_usejoy = 0, opt_ic_usemouse = 0, opt_ic_confkey = 0, opt_ic_confjoy = 0, opt_ic_confmouse = 0, opt_ic_confweap = 0, opt_ic_mouseflightsim = 0, opt_ic_joymousesens = 0, opt_ic_grabinput = 0, opt_ic_mousefsgauge = 0, opt_ic_help0 = 0, opt_ic_help1 = 0, opt_ic_help2 = 0; int input_config_menuset(newmenu *menu, d_event *event, void *userdata) { newmenu_item *items = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); userdata = userdata; switch (event->type) { case EVENT_NEWMENU_CHANGED: if (citem == opt_ic_usejoy) (items[citem].value)?(PlayerCfg.ControlType|=CONTROL_USING_JOYSTICK):(PlayerCfg.ControlType&=~CONTROL_USING_JOYSTICK); if (citem == opt_ic_usemouse) (items[citem].value)?(PlayerCfg.ControlType|=CONTROL_USING_MOUSE):(PlayerCfg.ControlType&=~CONTROL_USING_MOUSE); if (citem == opt_ic_mouseflightsim) PlayerCfg.MouseFlightSim = 0; if (citem == opt_ic_mouseflightsim+1) PlayerCfg.MouseFlightSim = 1; if (citem == opt_ic_grabinput) GameCfg.Grabinput = items[citem].value; if (citem == opt_ic_mousefsgauge) PlayerCfg.MouseFSIndicator = items[citem].value; break; case EVENT_NEWMENU_SELECTED: if (citem == opt_ic_confkey) kconfig(0, "KEYBOARD"); if (citem == opt_ic_confjoy) kconfig(1, "JOYSTICK"); if (citem == opt_ic_confmouse) kconfig(2, "MOUSE"); if (citem == opt_ic_confweap) kconfig(3, "WEAPON KEYS"); if (citem == opt_ic_joymousesens) input_config_sensitivity(); if (citem == opt_ic_help0) show_help(); if (citem == opt_ic_help1) show_netgame_help(); if (citem == opt_ic_help2) show_newdemo_help(); return 1; // stay in menu break; default: break; } return 0; } void input_config() { newmenu_item m[20]; int nitems = 0; opt_ic_usejoy = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "USE JOYSTICK"; m[nitems].value = (PlayerCfg.ControlType&CONTROL_USING_JOYSTICK); nitems++; opt_ic_usemouse = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "USE MOUSE"; m[nitems].value = (PlayerCfg.ControlType&CONTROL_USING_MOUSE); nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; opt_ic_confkey = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "CUSTOMIZE KEYBOARD"; nitems++; opt_ic_confjoy = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "CUSTOMIZE JOYSTICK"; nitems++; opt_ic_confmouse = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "CUSTOMIZE MOUSE"; nitems++; opt_ic_confweap = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "CUSTOMIZE WEAPON KEYS"; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "MOUSE CONTROL TYPE:"; nitems++; opt_ic_mouseflightsim = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "normal"; m[nitems].value = !PlayerCfg.MouseFlightSim; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "FlightSim"; m[nitems].value = PlayerCfg.MouseFlightSim; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; opt_ic_joymousesens = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "SENSITIVITY & DEADZONE"; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; opt_ic_grabinput = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text= "Keep Keyboard/Mouse focus"; m[nitems].value = GameCfg.Grabinput; nitems++; opt_ic_mousefsgauge = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text= "Mouse FlightSim Indicator"; m[nitems].value = PlayerCfg.MouseFSIndicator; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; opt_ic_help0 = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "GAME SYSTEM KEYS"; nitems++; opt_ic_help1 = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "NETGAME SYSTEM KEYS"; nitems++; opt_ic_help2 = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "DEMO SYSTEM KEYS"; nitems++; newmenu_do1(NULL, TXT_CONTROLS, nitems, m, input_config_menuset, NULL, 3); } void reticle_config() { #ifdef OGL newmenu_item m[18]; #else newmenu_item m[17]; #endif int nitems = 0, i, opt_ret_type, opt_ret_rgba, opt_ret_size; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Reticle Type:"; nitems++; opt_ret_type = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Classic"; m[nitems].value = 0; m[nitems].group = 0; nitems++; #ifdef OGL m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Classic Reboot"; m[nitems].value = 0; m[nitems].group = 0; nitems++; #endif m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "None"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "X"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Dot"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Circle"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Cross V1"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Cross V2"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Angle"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Reticle Color:"; nitems++; opt_ret_rgba = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Red"; m[nitems].value = (PlayerCfg.ReticleRGBA[0]/2); m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Green"; m[nitems].value = (PlayerCfg.ReticleRGBA[1]/2); m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Blue"; m[nitems].value = (PlayerCfg.ReticleRGBA[2]/2); m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Alpha"; m[nitems].value = (PlayerCfg.ReticleRGBA[3]/2); m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; opt_ret_size = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "Reticle Size:"; m[nitems].value = PlayerCfg.ReticleSize; m[nitems].min_value = 0; m[nitems].max_value = 4; nitems++; i = PlayerCfg.ReticleType; #ifndef OGL if (i > 1) i--; #endif m[opt_ret_type+i].value=1; newmenu_do1( NULL, "Reticle Options", nitems, m, NULL, NULL, 1 ); #ifdef OGL for (i = 0; i < 9; i++) if (m[i+opt_ret_type].value) PlayerCfg.ReticleType = i; #else for (i = 0; i < 8; i++) if (m[i+opt_ret_type].value) PlayerCfg.ReticleType = i; if (PlayerCfg.ReticleType > 1) PlayerCfg.ReticleType++; #endif for (i = 0; i < 4; i++) PlayerCfg.ReticleRGBA[i] = (m[i+opt_ret_rgba].value*2); PlayerCfg.ReticleSize = m[opt_ret_size].value; } int opt_gr_texfilt, opt_gr_brightness, opt_gr_reticlemenu, opt_gr_alphafx, opt_gr_dynlightcolor, opt_gr_vsync, opt_gr_multisample, opt_gr_fpsindi; int graphics_config_menuset(newmenu *menu, d_event *event, void *userdata) { newmenu_item *items = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); userdata = userdata; switch (event->type) { case EVENT_NEWMENU_CHANGED: if ( citem == opt_gr_texfilt + 3 #ifdef OGL && ogl_maxanisotropy <= 1.0 #endif ) { nm_messagebox( TXT_ERROR, 1, TXT_OK, "Anisotropic Filtering not\nsupported by your hardware/driver."); items[opt_gr_texfilt + 3].value = 0; items[opt_gr_texfilt + 2].value = 1; } if ( citem == opt_gr_brightness) gr_palette_set_gamma(items[citem].value); break; case EVENT_NEWMENU_SELECTED: if (citem == opt_gr_reticlemenu) reticle_config(); return 1; // stay in menu break; default: break; } return 0; } void graphics_config() { #ifdef OGL newmenu_item m[13]; int i = 0; #else newmenu_item m[3]; #endif int nitems = 0; #ifdef OGL m[nitems].type = NM_TYPE_TEXT; m[nitems].text = "Texture Filtering:"; nitems++; opt_gr_texfilt = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "None (Classical)"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Bilinear"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Trilinear"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "Anisotropic"; m[nitems].value = 0; m[nitems].group = 0; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text = ""; nitems++; #endif opt_gr_brightness = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_BRIGHTNESS; m[nitems].value = gr_palette_get_gamma(); m[nitems].min_value = 0; m[nitems].max_value = 16; nitems++; opt_gr_reticlemenu = nitems; m[nitems].type = NM_TYPE_MENU; m[nitems].text = "Reticle Options"; nitems++; #ifdef OGL opt_gr_alphafx = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Transparency Effects"; m[nitems].value = PlayerCfg.AlphaEffects; nitems++; opt_gr_dynlightcolor = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Colored Dynamic Light"; m[nitems].value = PlayerCfg.DynLightColor; nitems++; opt_gr_vsync = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text="VSync"; m[nitems].value = GameCfg.VSync; nitems++; opt_gr_multisample = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text="4x multisampling"; m[nitems].value = GameCfg.Multisample; nitems++; #endif opt_gr_fpsindi = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text="FPS Counter"; m[nitems].value = GameCfg.FPSIndicator; nitems++; #ifdef OGL m[opt_gr_texfilt+GameCfg.TexFilt].value=1; #endif newmenu_do1( NULL, "Graphics Options", nitems, m, graphics_config_menuset, NULL, 1 ); #ifdef OGL if (GameCfg.VSync != m[opt_gr_vsync].value || GameCfg.Multisample != m[opt_gr_multisample].value) nm_messagebox( NULL, 1, TXT_OK, "Setting VSync or 4x Multisample\nrequires restart on some systems."); for (i = 0; i <= 3; i++) if (m[i+opt_gr_texfilt].value) GameCfg.TexFilt = i; PlayerCfg.AlphaEffects = m[opt_gr_alphafx].value; PlayerCfg.DynLightColor = m[opt_gr_dynlightcolor].value; GameCfg.VSync = m[opt_gr_vsync].value; GameCfg.Multisample = m[opt_gr_multisample].value; #endif GameCfg.GammaLevel = m[opt_gr_brightness].value; GameCfg.FPSIndicator = m[opt_gr_fpsindi].value; #ifdef OGL gr_set_attributes(); gr_set_mode(Game_screen_mode); #endif } #if PHYSFS_VER_MAJOR >= 2 typedef struct browser { char *title; // The title - needed for making another listbox when changing directory int (*when_selected)(void *userdata, const char *filename); // What to do when something chosen void *userdata; // Whatever you want passed to when_selected char **list; // All menu items char *list_buf; // Buffer for menu item text: hopefully reduces memory fragmentation this way const char *const *ext_list; // List of file extensions we're looking for (if looking for a music file many types are possible) int select_dir; // Allow selecting the current directory (e.g. for Jukebox level song directory) int num_files; // Number of list items found (including parent directory and current directory if selectable) int max_files; // How many entries we can have before having to grow the array int max_buf; // How much text we can have before having to grow the buffer char view_path[PATH_MAX]; // The absolute path we're currently looking at int new_path; // Whether the view_path is a new searchpath, if so, remove it when finished } browser; void list_dir_el(browser *b, const char *origdir, const char *fname) { char *ext; const char *const *i = NULL; ext = strrchr(fname, '.'); if (ext) for (i = b->ext_list; *i != NULL && d_stricmp(ext, *i); i++) {} // see if the file is of a type we want if ((!strcmp((PHYSFS_getRealDir(fname)==NULL?"":PHYSFS_getRealDir(fname)), b->view_path)) && (PHYSFS_isDirectory(fname) || (ext && *i)) #if defined(__MACH__) && defined(__APPLE__) && d_stricmp(fname, "Volumes") // this messes things up, use '..' instead #endif ) string_array_add(&b->list, &b->list_buf, &b->num_files, &b->max_files, &b->max_buf, fname); } int list_directory(browser *b) { if (!string_array_new(&b->list, &b->list_buf, &b->num_files, &b->max_files, &b->max_buf)) return 0; strcpy(b->list_buf, ".."); // go to parent directory b->list[b->num_files++] = b->list_buf; if (b->select_dir) { b->list[b->num_files] = b->list[b->num_files - 1] + strlen(b->list[b->num_files - 1]) + 1; strcpy(b->list[b->num_files++], ""); // choose the directory being viewed } PHYSFS_enumerateFilesCallback("", (PHYSFS_EnumFilesCallback) list_dir_el, b); string_array_tidy(&b->list, &b->list_buf, &b->num_files, &b->max_files, &b->max_buf, 1 + (b->select_dir ? 1 : 0), #ifdef __LINUX__ strcmp #else d_stricmp #endif ); return 1; } static int select_file_recursive(char *title, const char *orig_path, const char *const *ext_list, int select_dir, int (*when_selected)(void *userdata, const char *filename), void *userdata); int select_file_handler(listbox *menu, d_event *event, browser *b) { char newpath[PATH_MAX]; char **list = listbox_get_items(menu); int citem = listbox_get_citem(menu); const char *sep = PHYSFS_getDirSeparator(); memset(newpath, 0, sizeof(char)*PATH_MAX); switch (event->type) { #ifdef _WIN32 case EVENT_KEY_COMMAND: { if (event_key_get(event) == KEY_CTRLED + KEY_D) { newmenu_item *m; char *text = NULL; int rval = 0; MALLOC(text, char, 2); MALLOC(m, newmenu_item, 1); snprintf(text, sizeof(char)*PATH_MAX, "c"); m->type=NM_TYPE_INPUT; m->text_len = 3; m->text = text; rval = newmenu_do( NULL, "Enter drive letter", 1, m, NULL, NULL ); text[1] = '\0'; snprintf(newpath, sizeof(char)*PATH_MAX, "%s:%s", text, sep); if (!rval && strlen(text)) { select_file_recursive(b->title, newpath, b->ext_list, b->select_dir, b->when_selected, b->userdata); // close old box. event->type = EVENT_WINDOW_CLOSED; window_close(listbox_get_window(menu)); } d_free(text); d_free(m); return 0; } break; } #endif case EVENT_NEWMENU_SELECTED: strcpy(newpath, b->view_path); if (citem == 0) // go to parent dir { char *p; if ((p = strstr(&newpath[strlen(newpath) - strlen(sep)], sep))) if (p != strstr(newpath, sep)) // if this isn't the only separator (i.e. it's not about to look at the root) *p = 0; p = newpath + strlen(newpath) - 1; while ((p > newpath) && strncmp(p, sep, strlen(sep))) // make sure full separator string is matched (typically is) p--; if (p == strstr(newpath, sep)) // Look at root directory next, if not already { #if defined(__MACH__) && defined(__APPLE__) if (!d_stricmp(p, "/Volumes")) return 1; #endif if (p[strlen(sep)] != '\0') p[strlen(sep)] = '\0'; else { #if defined(__MACH__) && defined(__APPLE__) // For Mac OS X, list all active volumes if we leave the root strcpy(newpath, "/Volumes"); #else return 1; #endif } } else *p = '\0'; } else if (citem == 1 && b->select_dir) return !(*b->when_selected)(b->userdata, ""); else { if (strncmp(&newpath[strlen(newpath) - strlen(sep)], sep, strlen(sep))) { strncat(newpath, sep, PATH_MAX - 1 - strlen(newpath)); newpath[PATH_MAX - 1] = '\0'; } strncat(newpath, list[citem], PATH_MAX - 1 - strlen(newpath)); newpath[PATH_MAX - 1] = '\0'; } if ((citem == 0) || PHYSFS_isDirectory(list[citem])) { // If it fails, stay in this one return !select_file_recursive(b->title, newpath, b->ext_list, b->select_dir, b->when_selected, b->userdata); } return !(*b->when_selected)(b->userdata, list[citem]); break; case EVENT_WINDOW_CLOSE: if (b->new_path) PHYSFS_removeFromSearchPath(b->view_path); if (list) d_free(list); if (b->list_buf) d_free(b->list_buf); d_free(b); break; default: break; } return 0; } static int select_file_recursive(char *title, const char *orig_path, const char *const *ext_list, int select_dir, int (*when_selected)(void *userdata, const char *filename), void *userdata) { browser *b; const char *sep = PHYSFS_getDirSeparator(); char *p; char new_path[PATH_MAX]; MALLOC(b, browser, 1); if (!b) return 0; b->title = title; b->when_selected = when_selected; b->userdata = userdata; b->ext_list = ext_list; b->select_dir = select_dir; b->num_files = b->max_files = 0; b->view_path[0] = '\0'; b->new_path = 1; // Check for a PhysicsFS path first, saves complication! if (orig_path && strncmp(orig_path, sep, strlen(sep)) && PHYSFSX_exists(orig_path,0)) { PHYSFSX_getRealPath(orig_path, new_path); orig_path = new_path; } // Set the viewing directory to orig_path, or some parent of it if (orig_path) { // Must make this an absolute path for directory browsing to work properly #ifdef _WIN32 if (!(isalpha(orig_path[0]) && (orig_path[1] == ':'))) // drive letter prompt (e.g. "C:" #elif defined(macintosh) if (orig_path[0] == ':') #else if (orig_path[0] != '/') #endif { strncpy(b->view_path, PHYSFS_getBaseDir(), PATH_MAX - 1); // current write directory must be set to base directory b->view_path[PATH_MAX - 1] = '\0'; #ifdef macintosh orig_path++; // go past ':' #endif strncat(b->view_path, orig_path, PATH_MAX - 1 - strlen(b->view_path)); b->view_path[PATH_MAX - 1] = '\0'; } else { strncpy(b->view_path, orig_path, PATH_MAX - 1); b->view_path[PATH_MAX - 1] = '\0'; } p = b->view_path + strlen(b->view_path) - 1; b->new_path = PHYSFSX_isNewPath(b->view_path); while (!PHYSFS_addToSearchPath(b->view_path, 0)) { while ((p > b->view_path) && strncmp(p, sep, strlen(sep))) p--; *p = '\0'; if (p == b->view_path) break; b->new_path = PHYSFSX_isNewPath(b->view_path); } } // Set to user directory if we couldn't find a searchpath if (!b->view_path[0]) { strncpy(b->view_path, PHYSFS_getUserDir(), PATH_MAX - 1); b->view_path[PATH_MAX - 1] = '\0'; b->new_path = PHYSFSX_isNewPath(b->view_path); if (!PHYSFS_addToSearchPath(b->view_path, 0)) { d_free(b); return 0; } } if (!list_directory(b)) { d_free(b); return 0; } return newmenu_listbox1(title, b->num_files, b->list, 1, 0, (int (*)(listbox *, d_event *, void *))select_file_handler, b) != NULL; } #define PATH_HEADER_TYPE NM_TYPE_MENU #define BROWSE_TXT " (browse...)" #else static int select_file_recursive(char *title, const char *orig_path, const char *const *ext_list, int select_dir, int (*when_selected)(void *userdata, const char *filename), void *userdata) { return 0; } #define PATH_HEADER_TYPE NM_TYPE_TEXT #define BROWSE_TXT #endif int opt_sm_digivol = -1, opt_sm_musicvol = -1, opt_sm_revstereo = -1, opt_sm_mtype0 = -1, opt_sm_mtype1 = -1, opt_sm_mtype2 = -1, opt_sm_mtype3 = -1, opt_sm_redbook_playorder = -1, opt_sm_mtype3_lmpath = -1, opt_sm_mtype3_lmplayorder1 = -1, opt_sm_mtype3_lmplayorder2 = -1, opt_sm_mtype3_lmplayorder3 = -1, opt_sm_cm_mtype3_file1_b = -1, opt_sm_cm_mtype3_file1 = -1, opt_sm_cm_mtype3_file2_b = -1, opt_sm_cm_mtype3_file2 = -1, opt_sm_cm_mtype3_file3_b = -1, opt_sm_cm_mtype3_file3 = -1, opt_sm_cm_mtype3_file4_b = -1, opt_sm_cm_mtype3_file4 = -1, opt_sm_cm_mtype3_file5_b = -1, opt_sm_cm_mtype3_file5 = -1; void set_extmusic_volume(int volume); int get_absolute_path(char *full_path, const char *rel_path) { PHYSFSX_getRealPath(rel_path, full_path); return 1; } #ifdef USE_SDLMIXER #define SELECT_SONG(t, s) select_file_recursive(t, GameCfg.CMMiscMusic[s], jukebox_exts, 0, (int (*)(void *, const char *))get_absolute_path, GameCfg.CMMiscMusic[s]) #endif int sound_menuset(newmenu *menu, d_event *event, void *userdata) { newmenu_item *items = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); //int nitems = newmenu_get_nitems(menu); int replay = 0; int rval = 0; switch (event->type) { case EVENT_NEWMENU_CHANGED: if (citem == opt_sm_digivol) { GameCfg.DigiVolume = items[citem].value; digi_set_digi_volume( (GameCfg.DigiVolume*32768)/8 ); digi_play_sample_once( SOUND_DROP_BOMB, F1_0 ); } else if (citem == opt_sm_musicvol) { GameCfg.MusicVolume = items[citem].value; songs_set_volume(GameCfg.MusicVolume); } else if (citem == opt_sm_revstereo) { GameCfg.ReverseStereo = items[citem].value; } else if (citem == opt_sm_mtype0) { GameCfg.MusicType = MUSIC_TYPE_NONE; replay = 1; } else if (citem == opt_sm_mtype1) { GameCfg.MusicType = MUSIC_TYPE_BUILTIN; replay = 1; } else if (citem == opt_sm_mtype2) { GameCfg.MusicType = MUSIC_TYPE_REDBOOK; replay = 1; } #ifdef USE_SDLMIXER else if (citem == opt_sm_mtype3) { GameCfg.MusicType = MUSIC_TYPE_CUSTOM; replay = 1; } #endif else if (citem == opt_sm_redbook_playorder) { GameCfg.OrigTrackOrder = items[citem].value; replay = (Game_wind != NULL); } #ifdef USE_SDLMIXER else if (citem == opt_sm_mtype3_lmplayorder1) { GameCfg.CMLevelMusicPlayOrder = MUSIC_CM_PLAYORDER_CONT; replay = (Game_wind != NULL); } else if (citem == opt_sm_mtype3_lmplayorder2) { GameCfg.CMLevelMusicPlayOrder = MUSIC_CM_PLAYORDER_LEVEL; replay = (Game_wind != NULL); } else if (citem == opt_sm_mtype3_lmplayorder3) { GameCfg.CMLevelMusicPlayOrder = MUSIC_CM_PLAYORDER_RAND; replay = (Game_wind != NULL); } #endif break; case EVENT_NEWMENU_SELECTED: #ifdef USE_SDLMIXER if (citem == opt_sm_mtype3_lmpath) { static const char *const ext_list[] = { ".m3u", NULL }; // select a directory or M3U playlist select_file_recursive( #ifndef _WIN32 "Select directory or\nM3U playlist to\n play level music from", #else "Select directory or\nM3U playlist to\n play level music from.\n CTRL-D to change drive", #endif GameCfg.CMLevelMusicPath, ext_list, 1, // look in current music path for ext_list files and allow directory selection (int (*)(void *, const char *))get_absolute_path, GameCfg.CMLevelMusicPath); // just copy the absolute path } else if (citem == opt_sm_cm_mtype3_file1_b) #ifndef _WIN32 SELECT_SONG("Select main menu music", SONG_TITLE); #else SELECT_SONG("Select main menu music.\nCTRL-D to change drive", SONG_TITLE); #endif else if (citem == opt_sm_cm_mtype3_file2_b) #ifndef _WIN32 SELECT_SONG("Select briefing music", SONG_BRIEFING); #else SELECT_SONG("Select briefing music.\nCTRL-D to change drive", SONG_BRIEFING); #endif else if (citem == opt_sm_cm_mtype3_file3_b) #ifndef _WIN32 SELECT_SONG("Select credits music", SONG_CREDITS); #else SELECT_SONG("Select credits music.\nCTRL-D to change drive", SONG_CREDITS); #endif else if (citem == opt_sm_cm_mtype3_file4_b) #ifndef _WIN32 SELECT_SONG("Select escape sequence music", SONG_ENDLEVEL); #else SELECT_SONG("Select escape sequence music.\nCTRL-D to change drive", SONG_ENDLEVEL); #endif else if (citem == opt_sm_cm_mtype3_file5_b) #ifndef _WIN32 SELECT_SONG("Select game ending music", SONG_ENDGAME); #else SELECT_SONG("Select game ending music.\nCTRL-D to change drive", SONG_ENDGAME); #endif #endif rval = 1; // stay in menu break; case EVENT_WINDOW_CLOSE: d_free(items); break; default: break; } if (replay) { songs_uninit(); if (Game_wind) songs_play_level_song( Current_level_num, 0 ); else songs_play_song(SONG_TITLE, 1); } userdata = userdata; return rval; } #ifdef USE_SDLMIXER #define SOUND_MENU_NITEMS 33 #else #ifdef _WIN32 #define SOUND_MENU_NITEMS 11 #else #define SOUND_MENU_NITEMS 10 #endif #endif void do_sound_menu() { newmenu_item *m; int nitems = 0; char old_CMLevelMusicPath[PATH_MAX+1], old_CMMiscMusic0[PATH_MAX+1]; memset(old_CMLevelMusicPath, 0, sizeof(char)*(PATH_MAX+1)); snprintf(old_CMLevelMusicPath, sizeof(old_CMLevelMusicPath), "%s", GameCfg.CMLevelMusicPath); memset(old_CMMiscMusic0, 0, sizeof(char)*(PATH_MAX+1)); snprintf(old_CMMiscMusic0, sizeof(old_CMMiscMusic0), "%s", GameCfg.CMMiscMusic[SONG_TITLE]); MALLOC(m, newmenu_item, SOUND_MENU_NITEMS); if (!m) return; opt_sm_digivol = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = TXT_FX_VOLUME; m[nitems].value = GameCfg.DigiVolume; m[nitems].min_value = 0; m[nitems++].max_value = 8; opt_sm_musicvol = nitems; m[nitems].type = NM_TYPE_SLIDER; m[nitems].text = "music volume"; m[nitems].value = GameCfg.MusicVolume; m[nitems].min_value = 0; m[nitems++].max_value = 8; opt_sm_revstereo = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = TXT_REVERSE_STEREO; m[nitems++].value = GameCfg.ReverseStereo; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "music type:"; opt_sm_mtype0 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "no music"; m[nitems].value = (GameCfg.MusicType == MUSIC_TYPE_NONE); m[nitems].group = 0; nitems++; #if defined(USE_SDLMIXER) || defined(_WIN32) opt_sm_mtype1 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "built-in/addon music"; m[nitems].value = (GameCfg.MusicType == MUSIC_TYPE_BUILTIN); m[nitems].group = 0; nitems++; #endif opt_sm_mtype2 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "cd music"; m[nitems].value = (GameCfg.MusicType == MUSIC_TYPE_REDBOOK); m[nitems].group = 0; nitems++; #ifdef USE_SDLMIXER opt_sm_mtype3 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "jukebox"; m[nitems].value = (GameCfg.MusicType == MUSIC_TYPE_CUSTOM); m[nitems].group = 0; nitems++; #endif m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; #ifdef USE_SDLMIXER m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "cd music / jukebox options:"; #else m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "cd music options:"; #endif opt_sm_redbook_playorder = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "force mac cd track order"; m[nitems++].value = GameCfg.OrigTrackOrder; #ifdef USE_SDLMIXER m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "jukebox options:"; opt_sm_mtype3_lmpath = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "path for level music" BROWSE_TXT; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMLevelMusicPath; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "level music play order:"; opt_sm_mtype3_lmplayorder1 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "continuously"; m[nitems].value = (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_CONT); m[nitems].group = 1; nitems++; opt_sm_mtype3_lmplayorder2 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "one track per level"; m[nitems].value = (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_LEVEL); m[nitems].group = 1; nitems++; opt_sm_mtype3_lmplayorder3 = nitems; m[nitems].type = NM_TYPE_RADIO; m[nitems].text = "random"; m[nitems].value = (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_RAND); m[nitems].group = 1; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = ""; m[nitems].type = NM_TYPE_TEXT; m[nitems++].text = "non-level music:"; opt_sm_cm_mtype3_file1_b = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "main menu" BROWSE_TXT; opt_sm_cm_mtype3_file1 = nitems; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMMiscMusic[SONG_TITLE]; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; opt_sm_cm_mtype3_file2_b = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "briefing" BROWSE_TXT; opt_sm_cm_mtype3_file2 = nitems; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMMiscMusic[SONG_BRIEFING]; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; opt_sm_cm_mtype3_file3_b = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "credits" BROWSE_TXT; opt_sm_cm_mtype3_file3 = nitems; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMMiscMusic[SONG_CREDITS]; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; opt_sm_cm_mtype3_file4_b = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "escape sequence" BROWSE_TXT; opt_sm_cm_mtype3_file4 = nitems; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMMiscMusic[SONG_ENDLEVEL]; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; opt_sm_cm_mtype3_file5_b = nitems; m[nitems].type = PATH_HEADER_TYPE; m[nitems++].text = "game ending" BROWSE_TXT; opt_sm_cm_mtype3_file5 = nitems; m[nitems].type = NM_TYPE_INPUT; m[nitems].text = GameCfg.CMMiscMusic[SONG_ENDGAME]; m[nitems++].text_len = NM_MAX_TEXT_LEN-1; #endif Assert(nitems == SOUND_MENU_NITEMS); newmenu_do1( NULL, "Sound Effects & Music", nitems, m, sound_menuset, NULL, 0 ); #ifdef USE_SDLMIXER if ( ((Game_wind != NULL) && strcmp(old_CMLevelMusicPath, GameCfg.CMLevelMusicPath)) || ((Game_wind == NULL) && strcmp(old_CMMiscMusic0, GameCfg.CMMiscMusic[SONG_TITLE])) ) { songs_uninit(); if (Game_wind) songs_play_level_song( Current_level_num, 0 ); else songs_play_song(SONG_TITLE, 1); } #endif } #define ADD_CHECK(n,txt,v) do { m[n].type=NM_TYPE_CHECK; m[n].text=txt; m[n].value=v;} while (0) void do_misc_menu() { newmenu_item m[10]; int i = 0; do { ADD_CHECK(0, "Ship auto-leveling", PlayerCfg.AutoLeveling); ADD_CHECK(1, "Persistent Debris",PlayerCfg.PersistentDebris); ADD_CHECK(2, "Screenshots w/o HUD",PlayerCfg.PRShot); ADD_CHECK(3, "No redundant pickup messages",PlayerCfg.NoRedundancy); ADD_CHECK(4, "Show Player chat only (Multi)",PlayerCfg.MultiMessages); ADD_CHECK(5, "No Rankings (Multi)",PlayerCfg.NoRankings); ADD_CHECK(6, "Show D2-style Prox. Bomb Gauge",PlayerCfg.BombGauge); ADD_CHECK(7, "Free Flight controls in Automap",PlayerCfg.AutomapFreeFlight); ADD_CHECK(8, "No Weapon Autoselect when firing",PlayerCfg.NoFireAutoselect); ADD_CHECK(9, "Only Cycle Autoselect Weapons",PlayerCfg.CycleAutoselectOnly); i = newmenu_do1( NULL, "Misc Options", sizeof(m)/sizeof(*m), m, NULL, NULL, i ); PlayerCfg.AutoLeveling = m[0].value; PlayerCfg.PersistentDebris = m[1].value; PlayerCfg.PRShot = m[2].value; PlayerCfg.NoRedundancy = m[3].value; PlayerCfg.MultiMessages = m[4].value; PlayerCfg.NoRankings = m[5].value; PlayerCfg.BombGauge = m[6].value; PlayerCfg.AutomapFreeFlight = m[7].value; PlayerCfg.NoFireAutoselect = m[8].value; PlayerCfg.CycleAutoselectOnly = m[9].value; } while( i>-1 ); } #if defined(USE_UDP) static int multi_player_menu_handler(newmenu *menu, d_event *event, int *menu_choice) { newmenu_item *items = newmenu_get_items(menu); switch (event->type) { case EVENT_NEWMENU_SELECTED: // stay in multiplayer menu, even after having played a game return do_option(menu_choice[newmenu_get_citem(menu)]); case EVENT_WINDOW_CLOSE: d_free(menu_choice); d_free(items); break; default: break; } return 0; } void do_multi_player_menu() { int *menu_choice; newmenu_item *m; int num_options = 0; MALLOC(menu_choice, int, 3); if (!menu_choice) return; MALLOC(m, newmenu_item, 3); if (!m) { d_free(menu_choice); return; } #ifdef USE_UDP m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_UDP_NETGAME; num_options++; #ifdef USE_TRACKER m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN/ONLINE GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++; #else m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++; #endif m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME MANUALLY"; menu_choice[num_options]=MENU_JOIN_MANUAL_UDP_NETGAME; num_options++; #endif newmenu_do3( NULL, TXT_MULTIPLAYER, num_options, m, (int (*)(newmenu *, d_event *, void *))multi_player_menu_handler, menu_choice, 0, NULL ); } #endif void do_options_menu() { newmenu_item *m; MALLOC(m, newmenu_item, 10); if (!m) return; m[ 0].type = NM_TYPE_MENU; m[ 0].text="Sound effects & music..."; m[ 1].type = NM_TYPE_TEXT; m[ 1].text=""; m[ 2].type = NM_TYPE_MENU; m[ 2].text=TXT_CONTROLS_; m[ 3].type = NM_TYPE_TEXT; m[ 3].text=""; m[ 4].type = NM_TYPE_MENU; m[ 4].text="Screen resolution..."; m[ 5].type = NM_TYPE_MENU; m[ 5].text="Graphics Options..."; m[ 6].type = NM_TYPE_TEXT; m[ 6].text=""; m[ 7].type = NM_TYPE_MENU; m[ 7].text="Primary autoselect ordering..."; m[ 8].type = NM_TYPE_MENU; m[ 8].text="Secondary autoselect ordering..."; m[ 9].type = NM_TYPE_MENU; m[ 9].text="Misc Options..."; // Fall back to main event loop // Allows clean closing and re-opening when resolution changes newmenu_do3( NULL, TXT_OPTIONS, 10, m, options_menuset, NULL, 0, NULL ); } #ifndef RELEASE int polygon_models_viewer_handler(window *wind, d_event *event) { static int view_idx = 0; int key = 0; static vms_angvec ang; switch (event->type) { case EVENT_WINDOW_ACTIVATED: key_toggle_repeat(1); view_idx = 0; ang.p = ang.b = 0; ang.h = F0_5-1; break; case EVENT_KEY_COMMAND: key = event_key_get(event); switch (key) { case KEY_ESC: window_close(wind); break; case KEY_SPACEBAR: view_idx ++; if (view_idx >= N_polygon_models) view_idx = 0; break; case KEY_BACKSP: view_idx --; if (view_idx < 0 ) view_idx = N_polygon_models - 1; break; case KEY_A: ang.h -= 100; break; case KEY_D: ang.h += 100; break; case KEY_W: ang.p -= 100; break; case KEY_S: ang.p += 100; break; case KEY_Q: ang.b -= 100; break; case KEY_E: ang.b += 100; break; case KEY_R: ang.p = ang.b = 0; ang.h = F0_5-1; break; default: break; } return 1; case EVENT_WINDOW_DRAW: timer_delay(F1_0/60); draw_model_picture(view_idx, &ang); gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(255,255,255), -1); gr_printf(FSPACX(1), FSPACY(1), "ESC: leave\nSPACE/BACKSP: next/prev model (%i/%i)\nA/D: rotate y\nW/S: rotate x\nQ/E: rotate z\nR: reset orientation",view_idx,N_polygon_models-1); break; case EVENT_WINDOW_CLOSE: key_toggle_repeat(0); break; default: break; } return 0; } void polygon_models_viewer() { window *wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))polygon_models_viewer_handler, NULL); if (!wind) { d_event event = { EVENT_WINDOW_CLOSE }; polygon_models_viewer_handler(NULL, &event); return; } while (window_exists(wind)) event_process(); } int gamebitmaps_viewer_handler(window *wind, d_event *event) { static int view_idx = 0; int key = 0; #ifdef OGL float scale = 1.0; #endif bitmap_index bi; grs_bitmap *bm; extern int Num_bitmap_files; switch (event->type) { case EVENT_WINDOW_ACTIVATED: key_toggle_repeat(1); view_idx = 0; break; case EVENT_KEY_COMMAND: key = event_key_get(event); switch (key) { case KEY_ESC: window_close(wind); break; case KEY_SPACEBAR: view_idx ++; if (view_idx >= Num_bitmap_files) view_idx = 0; break; case KEY_BACKSP: view_idx --; if (view_idx < 0 ) view_idx = Num_bitmap_files - 1; break; default: break; } return 1; case EVENT_WINDOW_DRAW: bi.index = view_idx; bm = &GameBitmaps[view_idx]; timer_delay(F1_0/60); PIGGY_PAGE_IN(bi); gr_clear_canvas( BM_XRGB(0,0,0) ); #ifdef OGL scale = (bm->bm_w > bm->bm_h)?(SHEIGHT/bm->bm_w)*0.8:(SHEIGHT/bm->bm_h)*0.8; ogl_ubitmapm_cs((SWIDTH/2)-(bm->bm_w*scale/2),(SHEIGHT/2)-(bm->bm_h*scale/2),bm->bm_w*scale,bm->bm_h*scale,bm,-1,F1_0); #else gr_bitmap((SWIDTH/2)-(bm->bm_w/2), (SHEIGHT/2)-(bm->bm_h/2), bm); #endif gr_set_curfont(GAME_FONT); gr_set_fontcolor(BM_XRGB(255,255,255), -1); gr_printf(FSPACX(1), FSPACY(1), "ESC: leave\nSPACE/BACKSP: next/prev bitmap (%i/%i)",view_idx,Num_bitmap_files-1); break; case EVENT_WINDOW_CLOSE: key_toggle_repeat(0); break; default: break; } return 0; } void gamebitmaps_viewer() { window *wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))gamebitmaps_viewer_handler, NULL); if (!wind) { d_event event = { EVENT_WINDOW_CLOSE }; gamebitmaps_viewer_handler(NULL, &event); return; } while (window_exists(wind)) event_process(); } int sandbox_menuset(newmenu *menu, d_event *event, void *userdata) { switch (event->type) { case EVENT_NEWMENU_CHANGED: break; case EVENT_NEWMENU_SELECTED: switch(newmenu_get_citem(menu)) { case 0: polygon_models_viewer(); break; case 1: gamebitmaps_viewer(); break; } return 1; // stay in menu until escape break; case EVENT_WINDOW_CLOSE: { newmenu_item *items = newmenu_get_items(menu); d_free(items); break; } default: break; } userdata = userdata; //kill warning return 0; } void do_sandbox_menu() { newmenu_item *m; MALLOC(m, newmenu_item, 2); if (!m) return; m[ 0].type = NM_TYPE_MENU; m[ 0].text="Polygon_models viewer"; m[ 1].type = NM_TYPE_MENU; m[ 1].text="GameBitmaps viewer"; newmenu_do3( NULL, "Coder's sandbox", 2, m, sandbox_menuset, NULL, 0, NULL ); } #endif dxx-rebirth-0.58.1-d1x/main/menu.h000066400000000000000000000025051217717257200166150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Menu prototypes and variables * */ #ifndef _MENU_H #define _MENU_H extern int hide_menus(void); extern void show_menus(void); // called once at program startup to get the player's name extern int RegisterPlayer(); // returns number of item chosen extern int DoMenu(); extern void do_options_menu(); extern int select_demo(void); #define Menu_pcx_name (((SWIDTH>=640&&SHEIGHT>=480) && PHYSFSX_exists("menuh.pcx",1))?"menuh.pcx":"menu.pcx") #define STARS_BACKGROUND (((SWIDTH>=640&&SHEIGHT>=480) && PHYSFSX_exists("starsb.pcx",1))?"starsb.pcx":"stars.pcx") extern char *menu_difficulty_text[]; #endif dxx-rebirth-0.58.1-d1x/main/mglobal.c000066400000000000000000000061071217717257200172630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Global variables for main directory * */ #include "fix.h" #include "vecmat.h" #include "inferno.h" #include "segment.h" #include "object.h" #include "bm.h" #include "3d.h" #include "game.h" // Global array of vertices, common to one mine. vms_vector Vertices[MAX_VERTICES]; g3s_point Segment_points[MAX_VERTICES]; fix FrameTime = 0x1000; // Time since last frame, in seconds fix64 GameTime64 = 0; // Time in game, in seconds int d_tick_count = 0; // increments every 50ms int d_tick_step = 0; // true once every 50ms // This is the global mine which create_new_mine returns. segment Segments[MAX_SEGMENTS]; //lsegment Lsegments[MAX_SEGMENTS]; // Number of vertices in current mine (ie, Vertices, pointed to by Vp) int Num_vertices = 0; int Num_segments = 0; int Highest_vertex_index=0; int Highest_segment_index=0; // Translate table to get opposite side of a face on a segment. char Side_opposite[MAX_SIDES_PER_SEGMENT] = {WRIGHT, WBOTTOM, WLEFT, WTOP, WFRONT, WBACK}; #define TOLOWER(c) ((((c)>='A') && ((c)<='Z'))?((c)+('a'-'A')):(c)) #ifdef PASSWORD #define encrypt(a,b,c,d) {a ^ TOLOWER((((int) PASSWORD)>>24)&255), \ b ^ TOLOWER((((int) PASSWORD)>>16)&255), \ c ^ TOLOWER((((int) PASSWORD)>>8)&255), \ d ^ TOLOWER((((int) PASSWORD))&255) } #else #define encrypt(a,b,c,d) { a,b,c,d } #endif sbyte Side_to_verts[MAX_SIDES_PER_SEGMENT][4] = { encrypt(7,6,2,3), // left encrypt(0,4,7,3), // top encrypt(0,1,5,4), // right encrypt(2,6,5,1), // bottom encrypt(4,5,6,7), // back encrypt(3,2,1,0), // front }; // Note, this MUST be the same as Side_to_verts, it is an int for speed reasons. int Side_to_verts_int[MAX_SIDES_PER_SEGMENT][4] = { encrypt(7,6,2,3), // left encrypt(0,4,7,3), // top encrypt(0,1,5,4), // right encrypt(2,6,5,1), // bottom encrypt(4,5,6,7), // back encrypt(3,2,1,0), // front }; // Texture map stuff int NumTextures = 0; bitmap_index Textures[MAX_TEXTURES]; // All textures. fix64 Next_laser_fire_time; // Time at which player can next fire his selected laser. fix64 Next_missile_fire_time; // Time at which player can next fire his selected missile. //--unused-- fix Laser_delay_time = F1_0/6; // Delay between laser fires. #define DEFAULT_DIFFICULTY 1 int Difficulty_level=DEFAULT_DIFFICULTY; // Difficulty level in 0..NDL-1, 0 = easiest, NDL-1 = hardest dxx-rebirth-0.58.1-d1x/main/mission.c000066400000000000000000000506261217717257200173340ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code to handle multiple missions * */ #include #include #include #include #include #include "pstypes.h" #include "strutil.h" #include "inferno.h" #include "mission.h" #include "gameseq.h" #include "titles.h" #include "songs.h" #include "dxxerror.h" #include "config.h" #include "newmenu.h" #include "text.h" #include "u_mem.h" #include "ignorecase.h" //values that describe where a mission is located enum mle_loc { ML_CURDIR = 0, ML_MISSIONDIR = 1 }; //mission list entry typedef struct mle { char *filename; // filename without extension int builtin_hogsize; // if it's the built-in mission, used for determining the version char mission_name[MISSION_NAME_LEN+1]; ubyte anarchy_only_flag; // if true, mission is anarchy only char *path; // relative file path enum mle_loc location; // where the mission is } mle; static int num_missions = -1; Mission *Current_mission = NULL; // currently loaded mission // Allocate the Level_names, Secret_level_names and Secret_level_table arrays static int allocate_levels(void) { MALLOC(Level_names, d_fname, Last_level); if (!Level_names) return 0; if (Last_secret_level) { N_secret_levels = -Last_secret_level; MALLOC(Secret_level_names, d_fname, N_secret_levels); if (!Secret_level_names) return 0; MALLOC(Secret_level_table, ubyte, N_secret_levels); if (!Secret_level_table) return 0; } return 1; } // // Special versions of mission routines for d1 builtins // int load_mission_d1(void) { int i; switch (PHYSFSX_fsize("descent.hog")) { case D1_SHAREWARE_MISSION_HOGSIZE: case D1_SHAREWARE_10_MISSION_HOGSIZE: N_secret_levels = 0; Last_level = 7; Last_secret_level = 0; if (!allocate_levels()) { free_mission(); return 0; } //build level names for (i=0;imission_name,e1->mission_name); } //returns 1 if file read ok, else 0 int read_mission_file(mle *mission, char *filename, int location) { char filename2[100]; PHYSFS_file *mfile; switch (location) { case ML_MISSIONDIR: strcpy(filename2,MISSION_DIR); break; default: Int3(); //fall through case ML_CURDIR: strcpy(filename2,""); break; } strcat(filename2,filename); mfile = PHYSFSX_openReadBuffered(filename2); if (mfile) { char *p; char temp[PATH_MAX], *ext; strcpy(temp,filename); p = strrchr(temp, '/'); // get the filename at the end of the path if (!p) p = temp; else p++; if ((ext = strchr(p, '.')) == NULL) return 0; //missing extension *ext = 0; //kill extension mission->path = d_strdup(temp); mission->anarchy_only_flag = 0; mission->filename = mission->path + (p - temp); mission->location = location; p = get_parm_value("name",mfile); if (p) { char *t; if ((t=strchr(p,';'))!=NULL) *t=0; t = p + strlen(p)-1; while (isspace(*t)) *t-- = 0; // remove trailing whitespace if (strlen(p) > MISSION_NAME_LEN) p[MISSION_NAME_LEN] = 0; strncpy(mission->mission_name, p, MISSION_NAME_LEN + 1); } else { PHYSFS_close(mfile); d_free(mission->path); return 0; } p = get_parm_value("type",mfile); //get mission type if (p) mission->anarchy_only_flag = istok(p,"anarchy"); PHYSFS_close(mfile); return 1; } return 0; } void add_d1_builtin_mission_to_list(mle *mission) { int size; size = PHYSFSX_fsize("descent.hog"); if (size == -1) return; switch (size) { case D1_SHAREWARE_MISSION_HOGSIZE: case D1_SHAREWARE_10_MISSION_HOGSIZE: case D1_MAC_SHARE_MISSION_HOGSIZE: mission->filename = d_strdup(D1_MISSION_FILENAME); strcpy(mission->mission_name, D1_SHAREWARE_MISSION_NAME); mission->anarchy_only_flag = 0; break; case D1_OEM_MISSION_HOGSIZE: case D1_OEM_10_MISSION_HOGSIZE: mission->filename = d_strdup(D1_MISSION_FILENAME); strcpy(mission->mission_name, D1_OEM_MISSION_NAME); mission->anarchy_only_flag = 0; break; default: Warning("Unknown D1 hogsize %d\n", size); Int3(); // fall through case D1_MISSION_HOGSIZE: case D1_MISSION_HOGSIZE2: case D1_10_MISSION_HOGSIZE: case D1_MAC_MISSION_HOGSIZE: mission->filename = d_strdup(D1_MISSION_FILENAME); strcpy(mission->mission_name, D1_MISSION_NAME); mission->anarchy_only_flag = 0; break; } mission->anarchy_only_flag = 0; mission->builtin_hogsize = size; mission->path = mission->filename; num_missions++; } void add_missions_to_list(mle *mission_list, char *path, char *rel_path, int anarchy_mode) { char **find, **i, *ext; find = PHYSFS_enumerateFiles(path); for (i = find; *i != NULL; i++) { if (strlen(path) + strlen(*i) + 1 >= PATH_MAX) continue; // path is too long strcat(rel_path, *i); if (PHYSFS_isDirectory(path)) { strcat(rel_path, "/"); add_missions_to_list(mission_list, path, rel_path, anarchy_mode); *(strrchr(path, '/')) = 0; } else if ((ext = strrchr(*i, '.')) && (!d_strnicmp(ext, ".msn", 4) || !d_strnicmp(ext, ".mn2", 4))) if (read_mission_file(&mission_list[num_missions], rel_path, ML_MISSIONDIR)) { if (anarchy_mode || !mission_list[num_missions].anarchy_only_flag) { mission_list[num_missions].builtin_hogsize = 0; num_missions++; } else d_free(mission_list[num_missions].path); } if (num_missions >= MAX_MISSIONS) { break; } (strrchr(path, '/'))[1] = 0; // chop off the entry } PHYSFS_freeList(find); } /* move to on mission list, increment */ void promote (mle *mission_list, char * mission_name, int * top_place) { int i; char name[FILENAME_LEN], * t; strcpy(name, mission_name); if ((t = strchr(name,'.')) != NULL) *t = 0; //kill extension for (i = *top_place; i < num_missions; i++) if (!d_stricmp(mission_list[i].filename, name)) { //swap mission positions mle temp; temp = mission_list[*top_place]; mission_list[*top_place] = mission_list[i]; mission_list[i] = temp; ++(*top_place); break; } } void free_mission(void) { // May become more complex with the editor if (Current_mission) { if (Current_mission->path && !PLAYING_BUILTIN_MISSION) { char hogpath[PATH_MAX]; sprintf(hogpath, MISSION_DIR "%s.hog", Current_mission->path); PHYSFSX_contfile_close(hogpath); } if (Current_mission->path) d_free(Current_mission->path); if (Level_names) d_free(Level_names); if(Secret_level_names) d_free(Secret_level_names); if(Secret_level_table) d_free(Secret_level_table); d_free(Current_mission); } } //fills in the global list of missions. Returns the number of missions //in the list. If anarchy_mode is set, then also add anarchy-only missions. mle *build_mission_list(int anarchy_mode) { mle *mission_list; int top_place; char search_str[PATH_MAX] = MISSION_DIR; //now search for levels on disk //@@Took out this code because after this routine was called once for //@@a list of single-player missions, a subsequent call for a list of //@@anarchy missions would not scan again, and thus would not find the //@@anarchy-only missions. If we retain the minimum level of install, //@@we may want to put the code back in, having it always scan for all //@@missions, and have the code that uses it sort out the ones it wants. //@@ if (num_missions != -1) { //@@ if (Current_mission_num != 0) //@@ load_mission(0); //set built-in mission as default //@@ return num_missions; //@@ } MALLOC(mission_list, mle, MAX_MISSIONS); num_missions = 0; add_d1_builtin_mission_to_list(mission_list + num_missions); add_missions_to_list(mission_list, search_str, search_str + strlen(search_str), anarchy_mode); // move original missions (in story-chronological order) // to top of mission list top_place = 0; promote(mission_list, "", &top_place); // original descent 1 mission if (num_missions > top_place) qsort(&mission_list[top_place], num_missions - top_place, sizeof(*mission_list), (int (*)( const void *, const void * ))ml_sort_func); if (num_missions > top_place) qsort(&mission_list[top_place], num_missions - top_place, sizeof(*mission_list), (int (*)( const void *, const void * ))ml_sort_func); return mission_list; } void free_mission_list(mle *mission_list) { int i; for (i = 0; i < num_missions; i++) d_free(mission_list[i].path); d_free(mission_list); num_missions = 0; } void init_extra_robot_movie(char *filename); //values for built-in mission //loads the specfied mission from the mission list. //build_mission_list() must have been called. //Returns true if mission loaded ok, else false. int load_mission(mle *mission) { PHYSFS_file *mfile; char buf[PATH_MAX], *v; if (Current_mission) free_mission(); Current_mission = d_malloc(sizeof(Mission)); if (!Current_mission) return 0; *(mle *) Current_mission = *mission; Current_mission->path = d_strdup(mission->path); Current_mission->filename = Current_mission->path + (mission->filename - mission->path); Current_mission->n_secret_levels = 0; //init vars Last_level = 0; Last_secret_level = 0; memset(&Briefing_text_filename, '\0', sizeof(Briefing_text_filename)); memset(&Ending_text_filename, '\0', sizeof(Ending_text_filename)); Secret_level_table = NULL; Level_names = NULL; Secret_level_names = NULL; // for Descent 1 missions, load descent.hog if (!PHYSFSX_contfile_init("descent.hog", 1)) Error("descent.hog not available!\n"); if (!d_stricmp(Current_mission_filename, D1_MISSION_FILENAME)) return load_mission_d1(); //read mission from file switch (mission->location) { case ML_MISSIONDIR: strcpy(buf,MISSION_DIR); break; default: Int3(); //fall through case ML_CURDIR: strcpy(buf,""); break; } strcat(buf, mission->path); strcat(buf,".msn"); PHYSFSEXT_locateCorrectCase(buf); mfile = PHYSFSX_openReadBuffered(buf); if (mfile == NULL) { free_mission(); return 0; //error! } //for non-builtin missions, load HOG strcpy(buf+strlen(buf)-4,".hog"); //change extension PHYSFSEXT_locateCorrectCase(buf); if (PHYSFSX_exists(buf,1)) PHYSFSX_contfile_init(buf, 0); snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Briefing_text_filename,1)) snprintf(Briefing_text_filename, sizeof(Briefing_text_filename), "%s.txb",Current_mission_filename); snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.tex",Current_mission_filename); if (!PHYSFSX_exists(Ending_text_filename,1)) snprintf(Ending_text_filename, sizeof(Ending_text_filename), "%s.txb",Current_mission_filename); while (PHYSFSX_fgets(buf,sizeof(buf),mfile)) { if (istok(buf,"type")) continue; //already have name, go to next line else if (istok(buf,"briefing")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"ending")) { if ((v = get_value(buf)) != NULL) { add_term(v); if (strlen(v) < FILENAME_LEN && strlen(v) > 0) { char *tmp, *ptr; MALLOC(tmp, char, FILENAME_LEN); snprintf(tmp, FILENAME_LEN, "%s", v); if ((ptr = strrchr(tmp, '.'))) // if there's a filename extension, kill it. No one knows it's the right one. *ptr = '\0'; strncat(tmp, ".tex", sizeof(char)*FILENAME_LEN); // apply tex-extenstion if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Briefing_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... else // ... otherwise ... { if ((ptr = strrchr(tmp, '.'))) *ptr = '\0'; strncat(tmp, ".txb", sizeof(char)*FILENAME_LEN); // apply txb extension if (PHYSFSX_exists(tmp,1)) // check if this file exists ... snprintf(Ending_text_filename, FILENAME_LEN, "%s", tmp); // ... and apply ... } d_free(tmp); } } } else if (istok(buf,"num_levels")) { if ((v=get_value(buf))!=NULL) { int n_levels,i; n_levels = atoi(v); Assert(n_levels <= MAX_LEVELS_PER_MISSION); n_levels = min(n_levels, MAX_LEVELS_PER_MISSION); MALLOC(Level_names, d_fname, n_levels); if (!Level_names) { free_mission(); return 0; } for (i=0;iLast_level) break; Last_secret_level--; } else break; } } } } PHYSFS_close(mfile); if (Last_level <= 0) { free_mission(); //no valid mission loaded return 0; } return 1; } //loads the named mission if exists. //Returns true if mission loaded ok, else false. int load_mission_by_name(char *mission_name) { int i; mle *mission_list = build_mission_list(1); bool found = 0; for (i = 0; i < num_missions; i++) if (!d_stricmp(mission_name, mission_list[i].filename)) found = load_mission(mission_list + i); free_mission_list(mission_list); return found; } typedef struct mission_menu { mle *mission_list; int (*when_selected)(void); } mission_menu; int mission_menu_handler(listbox *lb, d_event *event, mission_menu *mm) { char **list = listbox_get_items(lb); int citem = listbox_get_citem(lb); switch (event->type) { case EVENT_NEWMENU_SELECTED: if (citem >= 0) { // Chose a mission strcpy(GameCfg.LastMission, list[citem]); if (!load_mission(mm->mission_list + citem)) { nm_messagebox( NULL, 1, TXT_OK, TXT_MISSION_ERROR); return 1; // stay in listbox so user can select another one } } return !(*mm->when_selected)(); break; case EVENT_WINDOW_CLOSE: free_mission_list(mm->mission_list); d_free(list); d_free(mm); break; default: break; } return 0; } int select_mission(int anarchy_mode, char *message, int (*when_selected)(void)) { mle *mission_list = build_mission_list(anarchy_mode); int new_mission_num; if (num_missions <= 1) { new_mission_num = load_mission(mission_list) ? 0 : -1; free_mission_list(mission_list); (*when_selected)(); return (new_mission_num >= 0); } else { mission_menu *mm; int i, default_mission; char **m; MALLOC(m, char *, num_missions); if (!m) { free_mission_list(mission_list); return 0; } MALLOC(mm, mission_menu, 1); if (!mm) { d_free(m); free_mission_list(mission_list); return 0; } mm->mission_list = mission_list; mm->when_selected = when_selected; default_mission = 0; for (i = 0; i < num_missions; i++) { m[i] = mission_list[i].mission_name; if ( !d_stricmp( m[i], GameCfg.LastMission ) ) default_mission = i; } newmenu_listbox1( message, num_missions, m, 1, default_mission, (int (*)(listbox *, d_event *, void *))mission_menu_handler, mm ); } return 1; // presume success } #ifdef EDITOR void create_new_mission(void) { if (Current_mission) free_mission(); Current_mission = d_malloc(sizeof(Mission)); if (!Current_mission) return; memset(Current_mission, 0, sizeof(Mission)); Current_mission->path = d_strdup("new_mission"); if (!Current_mission->path) { free_mission(); return; } Current_mission->filename = Current_mission->path; MALLOC(Level_names, d_fname, 1); if (!Level_names) { free_mission(); return; } strcpy(Level_names[0], "GAMESAVE.LVL"); } #endif dxx-rebirth-0.58.1-d1x/main/mission.h000066400000000000000000000101511217717257200173260ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for mission.h * */ #ifndef _MISSION_H #define _MISSION_H #include "pstypes.h" #include "inferno.h" #define MAX_MISSIONS 5000 // ZICO - changed from 300 to get more levels in list #define MAX_LEVELS_PER_MISSION 127 // KREATOR - increased from 30 (limited by Demo and Multiplayer code) #define MAX_SECRET_LEVELS_PER_MISSION 127 // KREATOR - increased from 6 (limited by Demo and Multiplayer code) #define MISSION_NAME_LEN 25 #define D1_MISSION_FILENAME "" #define D1_MISSION_NAME "Descent: First Strike" #define D1_MISSION_HOGSIZE 6856701 // v1.4 - 1.5 #define D1_MISSION_HOGSIZE2 6856183 // v1.4 - 1.5 - different patch-way #define D1_10_MISSION_HOGSIZE 7261423 // v1.0 #define D1_MAC_MISSION_HOGSIZE 7456179 #define D1_OEM_MISSION_NAME "Destination Saturn" #define D1_OEM_MISSION_HOGSIZE 4492107 // v1.4a #define D1_OEM_10_MISSION_HOGSIZE 4494862 // v1.0 #define D1_SHAREWARE_MISSION_NAME "Descent Demo" #define D1_SHAREWARE_MISSION_HOGSIZE 2339773 // v1.4 #define D1_SHAREWARE_10_MISSION_HOGSIZE 2365676 // v1.0 - 1.2 #define D1_MAC_SHARE_MISSION_HOGSIZE 3370339 //where the missions go #define MISSION_DIR "missions/" typedef struct { char *filename; // filename int builtin_hogsize; // the size of the hogfile for a builtin mission, and 0 for an add-on mission char mission_name[MISSION_NAME_LEN+1]; ubyte anarchy_only_flag; // if true, mission is only for anarchy char *path; // relative file path d_fname briefing_text_filename; // name of briefing file d_fname ending_text_filename; // name of ending file ubyte last_level; sbyte last_secret_level; ubyte n_secret_levels; ubyte *secret_level_table; // originating level no for each secret level // arrays of names of the level files d_fname *level_names; d_fname *secret_level_names; } Mission; extern Mission *Current_mission; // current mission #define Current_mission_longname Current_mission->mission_name #define Current_mission_filename Current_mission->filename #define Briefing_text_filename Current_mission->briefing_text_filename #define Ending_text_filename Current_mission->ending_text_filename #define Last_level Current_mission->last_level #define Last_secret_level Current_mission->last_secret_level #define N_secret_levels Current_mission->n_secret_levels #define Secret_level_table Current_mission->secret_level_table #define Level_names Current_mission->level_names #define Secret_level_names Current_mission->secret_level_names #define PLAYING_BUILTIN_MISSION (Current_mission->builtin_hogsize != 0) #define ANARCHY_ONLY_MISSION (Current_mission->anarchy_only_flag == 1) #define BIMD1_LAST_LEVEL 27 #define BIMD1_LAST_SECRET_LEVEL -3 #define BIMD1_BRIEFING_FILE "briefing.txb" #define BIMD1_BRIEFING_FILE_OEM "briefsat.txb" #define BIMD1_ENDING_FILE "endreg.txb" #define BIMD1_ENDING_FILE_OEM "endsat.txb" #define BIMD1_ENDING_FILE_SHARE "ending.txb" //loads the named mission if it exists. //Returns true if mission loaded ok, else false. int load_mission_by_name (char *mission_name); //Handles creating and selecting from the mission list. //Returns 1 if a mission was loaded. int select_mission (int anarchy_mode, char *message, int (*when_selected)(void)); void free_mission(void); #ifdef EDITOR void create_new_mission(void); #endif #endif dxx-rebirth-0.58.1-d1x/main/morph.c000066400000000000000000000221631217717257200167730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Morphing code * */ #include #include #include #include "texmap.h" #include "dxxerror.h" #include "inferno.h" #include "morph.h" #include "polyobj.h" #include "game.h" #include "lighting.h" #include "newdemo.h" #include "piggy.h" #include "bm.h" morph_data morph_objects[MAX_MORPH_OBJECTS]; //returns ptr to data for this object, or NULL if none morph_data *find_morph_data(object *obj) { int i; if (Newdemo_state == ND_STATE_PLAYBACK) { morph_objects[0].obj = obj; return &morph_objects[0]; } for (i=0;imodel_data[pm->submodel_ptrs[submodel_num]]; type = *data++; Assert(type == 7 || type == 1); nverts = *data++; if (type==7) data+=2; //skip start & pad vp = (vms_vector *) data; *minv = *maxv = *vp++; nverts--; while (nverts--) { if (vp->x > maxv->x) maxv->x = vp->x; if (vp->y > maxv->y) maxv->y = vp->y; if (vp->z > maxv->z) maxv->z = vp->z; if (vp->x < minv->x) minv->x = vp->x; if (vp->y < minv->y) minv->y = vp->y; if (vp->z < minv->z) minv->z = vp->z; vp++; } } #define MORPH_RATE (f1_0*3) fix morph_rate = MORPH_RATE; void init_points(polymodel *pm,vms_vector *box_size,int submodel_num,morph_data *md) { ushort nverts; vms_vector *vp; ushort *data,type; int i; data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]]; type = *data++; Assert(type == 7 || type == 1); nverts = *data++; md->n_morphing_points[submodel_num] = 0; if (type==7) { i = *data++; //get start point number data++; //skip pad } else i = 0; //start at zero Assert(i+nverts < MAX_VECS); md->submodel_startpoints[submodel_num] = i; vp = (vms_vector *) data; while (nverts--) { fix k,dist; if (box_size) { fix t; k = 0x7fffffff; if (vp->x && f2i(box_size->x)x)/2 && (t = fixdiv(box_size->x,abs(vp->x))) < k) k=t; if (vp->y && f2i(box_size->y)y)/2 && (t = fixdiv(box_size->y,abs(vp->y))) < k) k=t; if (vp->z && f2i(box_size->z)z)/2 && (t = fixdiv(box_size->z,abs(vp->z))) < k) k=t; if (k==0x7fffffff) k=0; } else k=0; vm_vec_copy_scale(&md->morph_vecs[i],vp,k); dist = vm_vec_normalized_dir_quick(&md->morph_deltas[i],vp,&md->morph_vecs[i]); md->morph_times[i] = fixdiv(dist,morph_rate); if (md->morph_times[i] != 0) md->n_morphing_points[submodel_num]++; vm_vec_scale(&md->morph_deltas[i],morph_rate); vp++; i++; } } void update_points(polymodel *pm,int submodel_num,morph_data *md) { ushort nverts; vms_vector *vp; ushort *data,type; int i; data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]]; type = *data++; Assert(type == 7 || type == 1); nverts = *data++; if (type==7) { i = *data++; //get start point number data++; //skip pad } else i = 0; //start at zero vp = (vms_vector *) data; while (nverts--) { if (md->morph_times[i]) //not done yet { if ((md->morph_times[i] -= FrameTime) <= 0) { md->morph_vecs[i] = *vp; md->morph_times[i] = 0; md->n_morphing_points[submodel_num]--; } else vm_vec_scale_add2(&md->morph_vecs[i],&md->morph_deltas[i],FrameTime); } vp++; i++; } } //process the morphing object for one frame void do_morph_frame(object *obj) { int i; polymodel *pm; morph_data *md; md = find_morph_data(obj); if (md == NULL) { //maybe loaded half-morphed from disk obj->flags |= OF_SHOULD_BE_DEAD; //..so kill it return; } pm = &Polygon_models[md->obj->rtype.pobj_info.model_num]; for (i=0;in_models;i++) if (md->submodel_active[i]==1) { update_points(pm,i,md); if (md->n_morphing_points[i] == 0) { //maybe start submodel int t; md->submodel_active[i] = 2; //not animating, just visible md->n_submodels_active--; //this one done animating for (t=0;tn_models;t++) if (pm->submodel_parents[t] == i) { //start this one init_points(pm,NULL,t,md); md->n_submodels_active++; md->submodel_active[t] = 1; } } } if (!md->n_submodels_active) { //done morphing! md->obj->control_type = md->morph_save_control_type; md->obj->movement_type = md->morph_save_movement_type; md->obj->render_type = RT_POLYOBJ; md->obj->mtype.phys_info = md->morph_save_phys_info; md->obj = NULL; } } vms_vector morph_rotvel = {0x4000,0x2000,0x1000}; void init_morphs() { int i; for (i=0;itype==OBJ_NONE || morph_objects[i].obj->signature!=morph_objects[i].Morph_sig) break; if (i==MAX_MORPH_OBJECTS) //no free slots return; md = &morph_objects[i]; Assert(obj->render_type == RT_POLYOBJ); md->obj = obj; md->Morph_sig = obj->signature; md->morph_save_control_type = obj->control_type; md->morph_save_movement_type = obj->movement_type; md->morph_save_phys_info = obj->mtype.phys_info; Assert(obj->control_type == CT_AI); //morph objects are also AI objects obj->control_type = CT_MORPH; obj->render_type = RT_MORPH; obj->movement_type = MT_PHYSICS; //RT_NONE; obj->mtype.phys_info.rotvel = morph_rotvel; pm = &Polygon_models[obj->rtype.pobj_info.model_num]; find_min_max(pm,0,&pmmin,&pmmax); box_size.x = max(-pmmin.x,pmmax.x) / 2; box_size.y = max(-pmmin.y,pmmax.y) / 2; box_size.z = max(-pmmin.z,pmmax.z) / 2; for (i=0;imorph_times[i] = 0; for (i=1;isubmodel_active[i] = 0; md->submodel_active[0] = 1; //1 means visible & animating md->n_submodels_active = 1; //now, project points onto surface of box init_points(pm,&box_size,0,md); } void draw_model(polymodel *pm,int submodel_num,vms_angvec *anim_angles,g3s_lrgb light,morph_data *md) { int i,mn; int facing; int sort_list[MAX_SUBMODELS],sort_n; //first, sort the submodels sort_list[0] = submodel_num; sort_n = 1; for (i=0;in_models;i++) if (md->submodel_active[i] && pm->submodel_parents[i]==submodel_num) { facing = g3_check_normal_facing(&pm->submodel_pnts[i],&pm->submodel_norms[i]); if (!facing) sort_list[sort_n++] = i; else { //put at start int t; for (t=sort_n;t>0;t--) sort_list[t] = sort_list[t-1]; sort_list[0] = i; sort_n++; } } //now draw everything for (i=0;in_textures;i++) { texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]]; texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]].index]; } // Make sure the textures for this object are paged in... piggy_page_flushed = 0; for (i=0;in_textures;i++) PIGGY_PAGE_IN( texture_list_index[i] ); // Hmmm... cache got flushed in the middle of paging all these in, // so we need to reread them all in. if (piggy_page_flushed) { piggy_page_flushed = 0; for (i=0;in_textures;i++) PIGGY_PAGE_IN( texture_list_index[i] ); } // Make sure that they can all fit in memory. Assert( piggy_page_flushed == 0 ); g3_draw_morphing_model(&pm->model_data[pm->submodel_ptrs[submodel_num]],texture_list,anim_angles,light,&md->morph_vecs[md->submodel_startpoints[submodel_num]]); } else { vms_matrix orient; vm_angles_2_matrix(&orient,&anim_angles[mn]); g3_start_instance_matrix(&pm->submodel_offsets[mn],&orient); draw_model(pm,mn,anim_angles,light,md); g3_done_instance(); } } } void draw_morph_object(object *obj) { // int save_light; polymodel *po; g3s_lrgb light; morph_data *md; md = find_morph_data(obj); Assert(md != NULL); Assert(obj->rtype.pobj_info.model_num < N_polygon_models); po=&Polygon_models[obj->rtype.pobj_info.model_num]; light = compute_object_light(obj,NULL); g3_start_instance_matrix(&obj->pos,&obj->orient); g3_set_interp_points(robot_points); draw_model(po,0,obj->rtype.pobj_info.anim_angles,light,md); g3_done_instance(); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_morph_frame(md); } dxx-rebirth-0.58.1-d1x/main/morph.h000066400000000000000000000033511217717257200167760ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for morph.c * */ #ifndef _MORPH_H #define _MORPH_H #include "object.h" #define MAX_VECS 5000 typedef struct morph_data { object *obj; // object which is morphing vms_vector morph_vecs[MAX_VECS]; vms_vector morph_deltas[MAX_VECS]; fix morph_times[MAX_VECS]; int submodel_active[MAX_SUBMODELS]; // which submodels are active int n_morphing_points[MAX_SUBMODELS]; // how many active points in each part int submodel_startpoints[MAX_SUBMODELS]; // first point for each submodel int n_submodels_active; ubyte morph_save_control_type; ubyte morph_save_movement_type; physics_info morph_save_phys_info; int Morph_sig; } morph_data; #define MAX_MORPH_OBJECTS 5 extern morph_data morph_objects[]; void morph_start(object *obj); void draw_morph_object(object *obj); //process the morphing object for one frame void do_morph_frame(object *obj); //called at the start of a level void init_morphs(); extern morph_data *find_morph_data(object *obj); #endif dxx-rebirth-0.58.1-d1x/main/multi.c000066400000000000000000003277071217717257200170140ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Multiplayer code for network play. * */ #include #include #include #include #include "game.h" #include "multi.h" #include "object.h" #include "laser.h" #include "fuelcen.h" #include "scores.h" #include "gauges.h" #include "collide.h" #include "dxxerror.h" #include "fireball.h" #include "newmenu.h" #include "console.h" #include "wall.h" #include "cntrlcen.h" #include "powerup.h" #include "polyobj.h" #include "bm.h" #include "endlevel.h" #include "key.h" #include "playsave.h" #include "timer.h" #include "digi.h" #include "sounds.h" #include "newdemo.h" #include "text.h" #include "kmatrix.h" #include "multibot.h" #include "gameseq.h" #include "physics.h" #include "config.h" #include "hudmsg.h" #include "ctype.h" // for isalpha #include "vers_id.h" #include "byteswap.h" #include "pstypes.h" #include "strutil.h" #include "u_mem.h" #include "state.h" #ifdef USE_UDP #include "net_udp.h" #endif #include "args.h" // // Local macros and prototypes // // LOCALIZE ME!! #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0 void reset_player_object(void); // In object.c but not in object.h void multi_reset_object_texture(object *objp); void drop_player_eggs(object *playerobj); // from collide.c void multi_do_heartbeat(const ubyte *buf); void multi_send_heartbeat(); void multi_do_kill_goal_counts(const ubyte *buf); void multi_powcap_cap_objects(); void multi_powcap_adjust_remote_cap(int pnum); void multi_send_ranking(); void multi_new_bounty_target( int pnum ); void multi_do_bounty( const ubyte *buf ); void multi_save_game(ubyte slot, uint id, char *desc); void multi_restore_game(ubyte slot, uint id); void multi_do_save_game(const ubyte *buf); void multi_do_restore_game(const ubyte *buf); void multi_do_msgsend_state(const ubyte *buf); void multi_send_msgsend_state(int state); void multi_send_gmode_update(); void multi_do_gmode_update(const ubyte *buf); // // Global variables // int multi_protocol=0; // set and determinate used protocol int imulti_new_game=0; // to prep stuff for level only when starting new game int who_killed_controlcen = -1; // -1 = noone //do we draw the kill list on the HUD? int Show_kill_list = 1; int Show_reticle_name = 1; fix Show_kill_list_timer = 0; sbyte PKilledFlags[MAX_PLAYERS]; int Bounty_target = 0; int multi_sending_message[MAX_PLAYERS] = { 0,0,0,0,0,0,0,0 }; int multi_defining_message = 0; int multi_message_index = 0; ubyte multibuf[MAX_MULTI_MESSAGE_LEN+4]; // This is where multiplayer message are built unsigned char multibuf2[MAX_MULTI_MESSAGE_LEN+4]; short remote_to_local[MAX_PLAYERS][MAX_OBJECTS]; // Remote object number for each local object short local_to_remote[MAX_OBJECTS]; sbyte object_owner[MAX_OBJECTS]; // Who created each object in my universe, -1 = loaded at start int early_resp[MAX_PLAYERS]; // HACK in case we ger REAPPEAR packet before EXPLODE int Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote int Net_create_loc = 0; // pointer into previous array int Network_status = 0; char Network_message[MAX_MESSAGE_LEN]; int Network_message_reciever=-1; int sorted_kills[MAX_PLAYERS]; short kill_matrix[MAX_PLAYERS][MAX_PLAYERS]; int multi_goto_secret = 0; short team_kills[2]; int multi_quit_game = 0; const char GMNames[MULTI_GAME_TYPE_COUNT][MULTI_GAME_NAME_LENGTH]={ "Anarchy", "Team Anarchy", "Robo Anarchy", "Cooperative", "Unknown", "Unknown", "Unknown", "Bounty" }; const char GMNamesShrt[MULTI_GAME_TYPE_COUNT][8]={ "ANRCHY", "TEAM", "ROBO", "COOP", "UNKNOWN", "UNKNOWN", "UNKNOWN", "BOUNTY" }; // For rejoin object syncing (used here and all protocols - globally) int Network_send_objects = 0; // Are we in the process of sending objects to a player? int Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic? int Network_send_objnum = -1; // What object are we sending next? int Network_rejoined = 0; // Did WE rejoin this game? int Network_sending_extras=0; int VerifyPlayerJoined=-1; // Player (num) to enter game before any ingame/extra stuff is being sent int Player_joining_extras=-1; // This is so we know who to send 'latecomer' packets to. int Network_player_added = 0; // Is this a new player or a returning player? ushort my_segments_checksum = 0; netgame_info Netgame; bitmap_index multi_player_textures[MAX_PLAYERS][N_PLAYER_SHIP_TEXTURES]; // Globals for protocol-bound Refuse-functions char RefuseThisPlayer=0,WaitForRefuseAnswer=0,RefuseTeam,RefusePlayerName[12]; fix64 RefuseTimeLimit=0; char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES]; extern fix ThisLevelTime; extern void init_player_stats_new_ship(ubyte pnum); static const int message_length[] = { #define define_message_length(NAME,SIZE) (SIZE), for_each_multiplayer_command(, define_message_length, ) }; void multi_reset_player_object(object *objp); void multi_set_robot_ai(void); void multi_add_lifetime_killed(); void multi_add_lifetime_kills(); char *RankStrings[]={"(unpatched) ","Cadet ","Ensign ","Lieutenant ","Lt.Commander ", "Commander ","Captain ","Vice Admiral ","Admiral ","Demigod "}; int multi_allow_powerup_mask[MAX_POWERUP_TYPES] = { NETFLAG_DOINVUL, 0, 0, NETFLAG_DOLASER, 0, 0, 0, 0, 0, 0, 0, 0, NETFLAG_DOQUAD, NETFLAG_DOVULCAN, NETFLAG_DOSPREAD, NETFLAG_DOPLASMA, NETFLAG_DOFUSION, NETFLAG_DOPROXIM, NETFLAG_DOHOMING, NETFLAG_DOHOMING, NETFLAG_DOSMART, NETFLAG_DOMEGA, NETFLAG_DOVULCAN, NETFLAG_DOCLOAK, 0, NETFLAG_DOINVUL, 0, 0, 0 }; char *multi_allow_powerup_text[MULTI_ALLOW_POWERUP_MAX] = { #define define_netflag_string(NAME,STR) STR, for_each_netflag_value(define_netflag_string) }; int GetMyNetRanking() { int rank, eff; if (PlayerCfg.NetlifeKills+PlayerCfg.NetlifeKilled==0) return (1); rank=(int) (((float)PlayerCfg.NetlifeKills/3000.0)*8.0); eff=(int)((float)((float)PlayerCfg.NetlifeKills/((float)PlayerCfg.NetlifeKilled+(float)PlayerCfg.NetlifeKills))*100.0); if (rank>8) rank=8; if (eff<0) eff=0; if (eff<60) rank-=((59-eff)/10); if (rank<0) rank=0; if (rank>8) rank=8; return (rank+1); } void ClipRank (ubyte *rank) { // This function insures no crashes when dealing with D2 1.0 if (*rank > 9) *rank = 0; } // // Functions that replace what used to be macros // int objnum_remote_to_local(int remote_objnum, int owner) { // Map a remote object number from owner to a local object number int result; if ((owner >= N_players) || (owner < -1)) { Int3(); // Illegal! return(remote_objnum); } if (owner == -1) return(remote_objnum); if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS)) return(-1); result = remote_to_local[owner][remote_objnum]; if (result < 0) { return(-1); } return(result); } int objnum_local_to_remote(int local_objnum, sbyte *owner) { // Map a local object number to a remote + owner int result; if ((local_objnum < 0) || (local_objnum > Highest_object_index)) { *owner = -1; return(-1); } *owner = object_owner[local_objnum]; if (*owner == -1) return(local_objnum); if ((*owner >= N_players) || (*owner < -1)) { Int3(); // Illegal! *owner = -1; return local_objnum; } result = local_to_remote[local_objnum]; if (result < 0) { Int3(); // See Rob, object has no remote number! } return(result); } void map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner) { // Add a mapping from a network remote object number to a local one Assert(local_objnum > -1); Assert(remote_objnum > -1); Assert(owner > -1); Assert(owner != Player_num); Assert(local_objnum < MAX_OBJECTS); Assert(remote_objnum < MAX_OBJECTS); object_owner[local_objnum] = owner; remote_to_local[owner][remote_objnum] = local_objnum; local_to_remote[local_objnum] = remote_objnum; return; } void map_objnum_local_to_local(int local_objnum) { // Add a mapping for our locally created objects Assert(local_objnum > -1); Assert(local_objnum < MAX_OBJECTS); object_owner[local_objnum] = Player_num; remote_to_local[Player_num][local_objnum] = local_objnum; local_to_remote[local_objnum] = local_objnum; return; } void reset_network_objects() { memset(local_to_remote, -1, MAX_OBJECTS*sizeof(short)); memset(remote_to_local, -1, MAX_PLAYERS*MAX_OBJECTS*sizeof(short)); memset(object_owner, -1, MAX_OBJECTS); } int multi_objnum_is_past(int objnum) { switch (multi_protocol) { case MULTI_PROTO_UDP: #ifdef USE_UDP return net_udp_objnum_is_past(objnum); break; #endif default: Error("Protocol handling missing in multi_objnum_is_past\n"); break; } } // // Part 1 : functions whose main purpose in life is to divert the flow // of execution to either network specific code based // on the curretn Game_mode value. // // Show a score list to end of net players void multi_endlevel_score(void) { int i, old_connect=0, game_wind_visible = 0; // If there still is a Game_wind and it's suspended (usually both shoudl be the case), bring it up again so host can still take actions of the game if (Game_wind) { if (!window_is_visible(Game_wind)) { game_wind_visible = 1; window_set_visible(Game_wind, 1); } } // Save connect state and change to new connect state #ifdef NETWORK if (Game_mode & GM_NETWORK) { old_connect = Players[Player_num].connected; if (Players[Player_num].connected!=CONNECT_DIED_IN_MINE) Players[Player_num].connected = CONNECT_END_MENU; } #endif #ifdef NETWORK Network_status = NETSTAT_ENDLEVEL; #endif kmatrix_view(Game_mode & GM_NETWORK); // Restore connect state if (Game_mode & GM_NETWORK) { Players[Player_num].connected = old_connect; } if (Game_mode & GM_MULTI_COOP) { for (i = 0; i < Netgame.max_numplayers; i++) // Reset keys Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY); } for (i=0;i= MAX_PLAYERS) || (playernum < 0)) { Int3(); // Non-terminal, see Rob return; } obj = &Objects[Players[playernum].objnum]; obj->type = OBJ_GHOST; obj->render_type = RT_NONE; obj->movement_type = MT_NONE; multi_reset_player_object(obj); if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(playernum); } void multi_make_ghost_player(int playernum) { object *obj; // Assert(playernum != Player_num); // Assert(playernum < MAX_PLAYERS); if ((playernum == Player_num) || (playernum >= MAX_PLAYERS)) { Int3(); // Non-terminal, see rob return; } obj = &Objects[Players[playernum].objnum]; obj->type = OBJ_PLAYER; obj->movement_type = MT_PHYSICS; multi_reset_player_object(obj); if (playernum != Player_num) init_player_stats_new_ship(playernum); } int multi_get_kill_list(int *plist) { // Returns the number of active net players and their // sorted order of kills int i; int n = 0; for (i = 0; i < N_players; i++) //if (Players[sorted_kills[i]].connected) plist[n++] = sorted_kills[i]; if (n == 0) Int3(); // SEE ROB OR MATT //memcpy(plist, sorted_kills, N_players*sizeof(int)); return(n); } void multi_sort_kill_list(void) { // Sort the kills list each time a new kill is added int kills[MAX_PLAYERS]; int i; int changed = 1; for (i = 0; i < MAX_PLAYERS; i++) { if (Game_mode & GM_MULTI_COOP) kills[i] = Players[i].score; else kills[i] = Players[i].net_kills_total; } while (changed) { changed = 0; for (i = 0; i < N_players-1; i++) { if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]]) { changed = sorted_kills[i]; sorted_kills[i] = sorted_kills[i+1]; sorted_kills[i+1] = changed; changed = 1; } } } } extern object *obj_find_first_of_type (int); void multi_compute_kill(int killer, int killed) { // Figure out the results of a network kills and add it to the // appropriate player's tally. int killed_pnum, killed_type; int killer_pnum, killer_type; int TheGoal; char killed_name[(CALLSIGN_LEN*2)+4]; char killer_name[(CALLSIGN_LEN*2)+4]; // Both object numbers are localized already! if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index)) { Int3(); // See Rob, illegal value passed to compute_kill; return; } killed_type = Objects[killed].type; killer_type = Objects[killer].type; if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST)) { Int3(); // compute_kill passed non-player object! return; } killed_pnum = Objects[killed].id; Assert ((killed_pnum >= 0) && (killed_pnum < N_players)); if (Game_mode & GM_TEAM) sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]); else sprintf(killed_name, "%s", Players[killed_pnum].callsign); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_death(killed_pnum); digi_play_sample( SOUND_HUD_KILL, F3_0 ); if (killer_type == OBJ_CNTRLCEN) { Players[killed_pnum].net_killed_total++; Players[killed_pnum].net_kills_total--; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_kill(killed_pnum, -1); if (killed_pnum == Player_num) { HUD_init_message(HM_MULTI, "%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY); multi_add_lifetime_killed (); } else HUD_init_message(HM_MULTI, "%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY ); return; } else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST)) { if (killed_pnum == Player_num) { HUD_init_message(HM_MULTI, "%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT); multi_add_lifetime_killed(); } else HUD_init_message(HM_MULTI, "%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT ); Players[killed_pnum].net_killed_total++; return; } killer_pnum = Objects[killer].id; if (Game_mode & GM_TEAM) sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]); else sprintf(killer_name, "%s", Players[killer_pnum].callsign); // Beyond this point, it was definitely a player-player kill situation if ((killer_pnum < 0) || (killer_pnum >= N_players)) Int3(); // See rob, tracking down bug with kill HUD messages if ((killed_pnum < 0) || (killed_pnum >= N_players)) Int3(); // See rob, tracking down bug with kill HUD messages if (killer_pnum == killed_pnum) { if (Game_mode & GM_TEAM) { team_kills[get_team(killed_pnum)] -= 1; } Players[killed_pnum].net_killed_total += 1; Players[killed_pnum].net_kills_total -= 1; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_kill(killed_pnum, -1); kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides if (killer_pnum == Player_num) { HUD_init_message(HM_MULTI, "%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF ); multi_add_lifetime_killed(); } else HUD_init_message(HM_MULTI, "%s %s", killed_name, TXT_SUICIDE); /* Bounty mode needs some lovin' */ if( Game_mode & GM_BOUNTY && killed_pnum == Bounty_target && multi_i_am_master() ) { /* Select a random number */ int new = d_rand() % MAX_PLAYERS; /* Make sure they're valid: Don't check against kill flags, * just in case everyone's dead! */ while( !Players[new].connected ) new = d_rand() % MAX_PLAYERS; /* Select new target - it will be sent later when we're done with this function */ multi_new_bounty_target( new ); } } else { if (Game_mode & GM_TEAM) { if (get_team(killed_pnum) == get_team(killer_pnum)) { team_kills[get_team(killed_pnum)] -= 1; Players[killer_pnum].net_kills_total -= 1; } else { team_kills[get_team(killer_pnum)] += 1; Players[killer_pnum].net_kills_total += 1; Players[killer_pnum].KillGoalCount +=1; } } else if( Game_mode & GM_BOUNTY ) { /* Did the target die? Did the target get a kill? */ if( killed_pnum == Bounty_target || killer_pnum == Bounty_target ) { /* Increment kill counts */ Players[killer_pnum].net_kills_total++; Players[killer_pnum].KillGoalCount++; /* Record the kill in a demo */ if( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_multi_kill( killer_pnum, 1 ); /* If the target died, the new one is set! */ if( killed_pnum == Bounty_target ) multi_new_bounty_target( killer_pnum ); } } else { Players[killer_pnum].net_kills_total += 1; Players[killer_pnum].KillGoalCount+=1; } if (Newdemo_state == ND_STATE_RECORDING && !( Game_mode & GM_BOUNTY ) ) newdemo_record_multi_kill(killer_pnum, 1); Players[killed_pnum].net_killed_total += 1; kill_matrix[killer_pnum][killed_pnum] += 1; if (killer_pnum == Player_num) { HUD_init_message(HM_MULTI, "%s %s %s!", TXT_YOU, TXT_KILLED, killed_name); multi_add_lifetime_kills(); if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000)) add_points_to_score(-1000); } else if (killed_pnum == Player_num) { HUD_init_message(HM_MULTI, "%s %s %s!", killer_name, TXT_KILLED, TXT_YOU); multi_add_lifetime_killed(); } else HUD_init_message(HM_MULTI, "%s %s %s!", killer_name, TXT_KILLED, killed_name); } TheGoal=Netgame.KillGoal*5; if (Netgame.KillGoal>0) { if (Players[killer_pnum].KillGoalCount>=TheGoal) { if (killer_pnum==Player_num) { HUD_init_message_literal(HM_MULTI, "You reached the kill goal!"); Players[Player_num].shields=i2f(200); } else HUD_init_message(HM_MULTI, "%s has reached the kill goal!",Players[killer_pnum].callsign); HUD_init_message_literal(HM_MULTI, "The control center has been destroyed!"); net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN)); } } multi_sort_kill_list(); multi_show_player_list(); } void multi_do_protocol_frame(int force, int listen) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_do_frame(force, listen); break; #endif default: Error("Protocol handling missing in multi_do_protocol_frame\n"); break; } } void multi_do_frame(void) { static int lasttime=0; static fix64 last_update_time = 0; int i; if (!(Game_mode & GM_MULTI) || Newdemo_state == ND_STATE_PLAYBACK) { Int3(); return; } if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime)) { for (i=0;i= last_update_time + (F1_0*2)) { multi_send_gmode_update(); last_update_time = timer_query(); } multi_send_message(); // Send any waiting messages if (Game_mode & GM_MULTI_ROBOTS) { multi_check_robot_timeout(); } multi_do_protocol_frame(0, 1); if (multi_quit_game) { multi_quit_game = 0; if (Game_wind) window_close(Game_wind); } } void multi_send_data(unsigned char *buf, int len, int priority) { if (len != message_length[(int)buf[0]]) Error("multi_send_data: Packet type %i length: %i, expected: %i\n", buf[0], len, message_length[(int)buf[0]]); if (buf[0] >= sizeof(message_length) / sizeof(message_length[0])) Error("multi_send_data: Illegal packet type %i\n", buf[0]); if (Game_mode & GM_NETWORK) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_send_data(buf, len, priority); break; #endif default: Error("Protocol handling missing in multi_send_data\n"); break; } } } void multi_send_data_direct(const ubyte *buf, int len, int pnum, int priority) { if (len != message_length[(int)buf[0]]) Error("multi_send_data_direct: Packet type %i length: %i, expected: %i\n", buf[0], len, message_length[(int)buf[0]]); if (buf[0] >= sizeof(message_length) / sizeof(message_length[0])) Error("multi_send_data_direct: Illegal packet type %i\n", buf[0]); if (pnum < 0 || pnum > MAX_PLAYERS) Error("multi_send_data_direct: Illegal player num: %i\n", pnum); switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_send_mdata_direct(multibuf, len, pnum, priority); break; #endif default: Error("Protocol handling missing in multi_send_data_direct\n"); break; } } void multi_leave_game(void) { if (!(Game_mode & GM_MULTI)) return; if (Game_mode & GM_NETWORK) { Net_create_loc = 0; multi_send_position(Players[Player_num].objnum); multi_powcap_cap_objects(); if (!Player_eggs_dropped) { drop_player_eggs(ConsoleObject); Player_eggs_dropped = 1; } multi_send_player_explode(MULTI_PLAYER_DROP); } multi_send_quit(MULTI_QUIT); if (Game_mode & GM_NETWORK) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_leave_game(); break; #endif default: Error("Protocol handling missing in multi_leave_game\n"); break; } } plyr_save_stats(); } void multi_show_player_list() { if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP)) return; if (Show_kill_list) return; Show_kill_list_timer = F1_0*5; // 5 second timer Show_kill_list = 1; } int multi_endlevel(int *secret) { int result = 0; switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: result = net_udp_endlevel(secret); break; #endif default: Error("Protocol handling missing in multi_endlevel\n"); break; } return(result); } int multi_endlevel_poll1( newmenu *menu, d_event *event, void *userdata ) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: return net_udp_kmatrix_poll1( menu, event, userdata ); break; #endif default: Error("Protocol handling missing in multi_endlevel_poll1\n"); break; } return 0; // kill warning } int multi_endlevel_poll2( newmenu *menu, d_event *event, void *userdata ) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: return net_udp_kmatrix_poll2( menu, event, userdata ); break; #endif default: Error("Protocol handling missing in multi_endlevel_poll2\n"); break; } return 0; } void multi_send_endlevel_packet() { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_send_endlevel_packet(); break; #endif default: Error("Protocol handling missing in multi_send_endlevel_packet\n"); break; } } // // Part 2 : functions that act on network messages and change the // the state of the game in some way. // void multi_define_macro(int key) { if (!(Game_mode & GM_MULTI)) return; key &= (~KEY_SHIFTED); switch(key) { case KEY_F9: multi_defining_message = 1; break; case KEY_F10: multi_defining_message = 2; break; case KEY_F11: multi_defining_message = 3; break; case KEY_F12: multi_defining_message = 4; break; default: Int3(); } if (multi_defining_message) { key_toggle_repeat(1); multi_message_index = 0; Network_message[multi_message_index] = 0; } } char feedback_result[200]; void multi_message_feedback(void) { char *colon; int found = 0; int i; if (!( ((colon = strstr(Network_message, ": ")) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) )) { sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO); if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3)) { sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]); found = 1; } if (Game_mode & GM_TEAM) { for (i = 0; i < N_players; i++) { if (!d_strnicmp(Netgame.team_name[i], Network_message, colon-Network_message)) { if (found) strcat(feedback_result, ", "); found++; if (!(found % 4)) strcat(feedback_result, "\n"); sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]); } } } for (i = 0; i < N_players; i++) { if ((!d_strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected)) { if (found) strcat(feedback_result, ", "); found++; if (!(found % 4)) strcat(feedback_result, "\n"); sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign); } } if (!found) strcat(feedback_result, TXT_NOBODY); else strcat(feedback_result, "."); digi_play_sample(SOUND_HUD_MESSAGE, F1_0); Assert(strlen(feedback_result) < 200); HUD_init_message_literal(HM_MULTI, feedback_result); } } //added/moved on 11/10/98 by Victor Rachels to declare before this function void multi_send_message_end(); //end this section change - VR void multi_send_macro(int key) { if (! (Game_mode & GM_MULTI) ) return; switch(key) { case KEY_F9: key = 0; break; case KEY_F10: key = 1; break; case KEY_F11: key = 2; break; case KEY_F12: key = 3; break; default: Int3(); } if (!PlayerCfg.NetworkMessageMacro[key][0]) { HUD_init_message_literal(HM_MULTI, TXT_NO_MACRO); return; } strcpy(Network_message, PlayerCfg.NetworkMessageMacro[key]); Network_message_reciever = 100; HUD_init_message(HM_MULTI, "%s '%s'", TXT_SENDING, Network_message); multi_message_feedback(); } void multi_send_message_start() { if (Game_mode&GM_MULTI) { multi_sending_message[Player_num] = 1; multi_send_msgsend_state(1); multi_message_index = 0; Network_message[multi_message_index] = 0; key_toggle_repeat(1); } } extern fix StartingShields; void multi_send_message_end() { char *mytempbuf; int i,t; multi_message_index = 0; multi_sending_message[Player_num] = 0; multi_send_msgsend_state(0); key_toggle_repeat(0); if (!d_strnicmp (Network_message,"/Handicap: ",11)) { mytempbuf=&Network_message[11]; StartingShields=atol (mytempbuf); if (StartingShields<10) StartingShields=10; if (StartingShields>100) { sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign); StartingShields=100; } else sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields); HUD_init_message(HM_MULTI, "Telling others of your handicap of %d!",StartingShields); StartingShields=i2f(StartingShields); } else if (!d_strnicmp (Network_message,"/move: ",7)) { if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM)) { int name_index=7; if (strlen(Network_message) > 7) while (Network_message[name_index] == ' ') name_index++; if (!multi_i_am_master()) { HUD_init_message(HM_MULTI, "Only %s can move players!",Players[multi_who_is_master()].callsign); return; } if (strlen(Network_message)<=name_index) { HUD_init_message_literal(HM_MULTI, "You must specify a name to move"); return; } for (i = 0; i < N_players; i++) if ((!d_strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected)) { if (Netgame.team_vector & (1< 7) while (Network_message[name_index] == ' ') name_index++; if (!multi_i_am_master()) { HUD_init_message(HM_MULTI, "Only %s can kick others out!",Players[multi_who_is_master()].callsign); multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } if (strlen(Network_message)<=name_index) { HUD_init_message_literal(HM_MULTI, "You must specify a name to kick"); multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) { int players[MAX_PLAYERS]; int listpos = Network_message[name_index+1] - '0'; if (Show_kill_list==1 || Show_kill_list==2) { if (listpos == 0 || listpos >= N_players) { HUD_init_message_literal(HM_MULTI, "Invalid player number for kick."); multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } multi_get_kill_list(players); i = players[listpos]; if ((i != Player_num) && (Players[i].connected)) goto kick_player; } else HUD_init_message_literal(HM_MULTI, "You cannot use # kicking with in team display."); multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } for (i = 0; i < N_players; i++) if ((!d_strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) { kick_player:; switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_dump_player(Netgame.players[i].protocol.udp.addr, DUMP_KICKED); break; #endif default: Error("Protocol handling missing in multi_send_message_end\n"); break; } HUD_init_message(HM_MULTI, "Dumping %s...",Players[i].callsign); multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } } else if (!d_strnicmp (Network_message,"/killreactor",12) && (Game_mode & GM_NETWORK) && !Control_center_destroyed) { if (!multi_i_am_master()) HUD_init_message(HM_MULTI, "Only %s can kill the reactor this way!",Players[multi_who_is_master()].callsign); else { net_destroy_controlcen(NULL); multi_send_destroy_controlcen(-1,Player_num); } multi_message_index = 0; multi_sending_message[Player_num] = 0; return; } Network_message_reciever = 100; HUD_init_message(HM_MULTI, "%s '%s'", TXT_SENDING, Network_message); multi_send_message(); multi_message_feedback(); game_flush_inputs(); } void multi_define_macro_end() { Assert( multi_defining_message > 0 ); strcpy( PlayerCfg.NetworkMessageMacro[multi_defining_message-1], Network_message ); write_player_file(); multi_message_index = 0; multi_defining_message = 0; key_toggle_repeat(0); game_flush_inputs(); } int multi_message_input_sub(int key) { switch( key ) { case KEY_F8: case KEY_ESC: multi_sending_message[Player_num] = 0; multi_send_msgsend_state(0); multi_defining_message = 0; key_toggle_repeat(0); game_flush_inputs(); return 1; case KEY_LEFT: case KEY_BACKSP: case KEY_PAD4: if (multi_message_index > 0) multi_message_index--; Network_message[multi_message_index] = 0; return 1; case KEY_ENTER: if ( multi_sending_message[Player_num] ) multi_send_message_end(); else if ( multi_defining_message ) multi_define_macro_end(); game_flush_inputs(); return 1; default: { int ascii = key_ascii(); if ( ascii < 255 ) { if (multi_message_index < MAX_MESSAGE_LEN-2 ) { Network_message[multi_message_index++] = ascii; Network_message[multi_message_index] = 0; } else if ( multi_sending_message[Player_num] ) { int i; char * ptext, * pcolon; ptext = NULL; Network_message[multi_message_index++] = ascii; Network_message[multi_message_index] = 0; for (i=multi_message_index-1; i>=0; i-- ) { if ( Network_message[i]==32 ) { ptext = &Network_message[i+1]; Network_message[i] = 0; break; } } multi_send_message_end(); if ( ptext ) { multi_sending_message[Player_num] = 1; multi_send_msgsend_state(1); pcolon = strstr( Network_message, ": " ); if ( pcolon ) strcpy( pcolon+1, ptext ); else strcpy( Network_message, ptext ); multi_message_index = strlen( Network_message ); } } } } } return 0; } void multi_send_message_dialog(void) { newmenu_item m[1]; int choice; if (!(Game_mode&GM_MULTI)) return; Network_message[0] = 0; // Get rid of old contents m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1; choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL, NULL ); if ((choice > -1) && (strlen(Network_message) > 0)) { Network_message_reciever = 100; multi_message_feedback(); } } void multi_do_death(int objnum) { // Do any miscellaneous stuff for a new network player after death objnum = objnum; if (!(Game_mode & GM_MULTI_COOP)) { Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY); } } void multi_do_fire(const ubyte *buf) { ubyte weapon; int pnum; sbyte flags; fix save_charge = Fusion_charge; // Act out the actual shooting pnum = buf[1]; weapon = (int)buf[2]; flags = buf[4]; Network_laser_track = GET_INTEL_SHORT(buf + 6); Assert (pnum < N_players); if (Objects[Players[pnum].objnum].type == OBJ_GHOST) multi_make_ghost_player(pnum); if (weapon >= MISSILE_ADJUST) net_missile_firing(pnum, weapon, (int)buf[4]); else { if (weapon == FUSION_INDEX) { Fusion_charge = buf[4] << 12; } if (weapon == LASER_INDEX) { if (flags & LASER_QUAD) Players[pnum].flags |= PLAYER_FLAGS_QUAD_LASERS; else Players[pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS; } do_laser_firing(Players[pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]); if (weapon == FUSION_INDEX) Fusion_charge = save_charge; } } void multi_do_message(const ubyte *cbuf) { const char *buf = (const char*)cbuf; char *colon,mesbuf[100]; int t; int loc = 2; if (((colon = strstr(buf+loc, ": ")) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN)) { int color = 0; mesbuf[0] = CC_COLOR; if (Game_mode & GM_TEAM) color = get_team((int)buf[1]); else color = (int)buf[1]; mesbuf[1] = BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b); strcpy(&mesbuf[2], Players[(int)buf[1]].callsign); t = strlen(mesbuf); mesbuf[t] = ':'; mesbuf[t+1] = CC_COLOR; mesbuf[t+2] = BM_XRGB(0, 31, 0); mesbuf[t+3] = 0; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message(HM_MULTI, "%s %s", mesbuf, buf+2); multi_sending_message[(int)buf[1]] = 0; } else if ( (!d_strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) || ((Game_mode & GM_TEAM) && ( (get_team(Player_num) == atoi(buf+loc)-1) || !d_strnicmp(Netgame.team_name[get_team(Player_num)], buf+loc, colon-(buf+loc)))) ) { int color = 0; mesbuf[0] = CC_COLOR; if (Game_mode & GM_TEAM) color = get_team((int)buf[1]); else color = (int)buf[1]; mesbuf[1] = BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b); strcpy(&mesbuf[2], Players[(int)buf[1]].callsign); t = strlen(mesbuf); mesbuf[t] = ':'; mesbuf[t+1] = CC_COLOR; mesbuf[t+2] = BM_XRGB(0, 31, 0); mesbuf[t+3] = 0; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message(HM_MULTI, "%s %s", mesbuf, colon+2); multi_sending_message[(int)buf[1]] = 0; } } void multi_do_position(const ubyte *buf) { ubyte pnum = 0; #ifdef WORDS_BIGENDIAN shortpos sp; #endif pnum = buf[1]; #ifndef WORDS_BIGENDIAN extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf + 2),0); #else memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 2), 9); memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 11), 14); extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1); #endif if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS) set_thrust_from_velocity(&Objects[Players[pnum].objnum]); } void multi_do_reappear(const ubyte *buf) { short objnum; ubyte pnum = buf[1]; objnum = GET_INTEL_SHORT(buf + 2); Assert(objnum >= 0); if (pnum != Objects[objnum].id) return; if (PKilledFlags[pnum]<=0) // player was not reported dead, so do not accept this packet { PKilledFlags[pnum]--; return; } multi_make_ghost_player(Objects[objnum].id); create_player_appearance_effect(&Objects[objnum]); PKilledFlags[pnum]=0; } void multi_do_player_explode(const ubyte *buf) { // Only call this for players, not robots. pnum is player number, not // Object number. object *objp; int count; int pnum; int i; char remote_created; pnum = buf[1]; #ifdef NDEBUG if ((pnum < 0) || (pnum >= N_players)) return; #else Assert(pnum >= 0); Assert(pnum < N_players); #endif #ifdef NETWORK // If we are in the process of sending objects to a new player, reset that process if (Network_send_objects) { Network_send_objnum = -1; } #endif // Stuff the Players structure to prepare for the explosion count = 2; Players[pnum].primary_weapon_flags = buf[count]; count++; Players[pnum].secondary_weapon_flags = buf[count]; count++; Players[pnum].laser_level = buf[count]; count++; Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++; Players[pnum].secondary_ammo[SMART_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++; Players[pnum].primary_ammo[VULCAN_INDEX] = GET_INTEL_SHORT(buf + count); count += 2; Players[pnum].flags = GET_INTEL_INT(buf + count); count += 4; multi_powcap_adjust_remote_cap (pnum); objp = Objects+Players[pnum].objnum; // objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes // objp->pos = *(vms_vector *)(buf+28); // 12 bytes remote_created = buf[count++]; // How many did the other guy create? Net_create_loc = 0; drop_player_eggs(objp); // Create mapping from remote to local numbering system // We now handle this situation gracefully, Int3 not required // if (Net_create_loc != remote_created) // Int3(); // Probably out of object array space, see Rob for (i = 0; i < remote_created; i++) { short s; s = GET_INTEL_SHORT(buf + count); if ((i < Net_create_loc) && (s > 0) && (Net_create_objnums[i] > 0)) map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum); count += 2; } for (i = remote_created; i < Net_create_loc; i++) { Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD; } if (buf[0] == MULTI_PLAYER_EXPLODE) { explode_badass_player(objp); objp->flags &= ~OF_SHOULD_BE_DEAD; //don't really kill player multi_make_player_ghost(pnum); } else { create_player_appearance_effect(objp); } Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE); Players[pnum].cloak_time = 0; PKilledFlags[pnum]++; if (PKilledFlags[pnum] < 1) // seems we got reappear already so make him player again! { multi_make_ghost_player(Objects[Players[pnum].objnum].id); create_player_appearance_effect(&Objects[Players[pnum].objnum]); PKilledFlags[pnum] = 0; } } /* * Process can compute a kill. If I am a Client this might be my own one (see multi_send_kill()) but with more specific data so I can compute my kill correctly. */ void multi_do_kill(const ubyte *buf) { int killer, killed; int count = 1; int pnum = (int)(buf[count]); int type = (int)(buf[0]); if (multi_i_am_master() && type != MULTI_KILL_CLIENT) return; if (!multi_i_am_master() && type != MULTI_KILL_HOST) return; if ((pnum < 0) || (pnum >= N_players)) { Int3(); // Invalid player number killed return; } // I am host, I know what's going on so take this packet, add game_mode related info which might be necessary for kill computation and send it to everyone so they can compute their kills correctly if (multi_i_am_master()) { memcpy(multibuf, buf, 5); multibuf[0] = MULTI_KILL_HOST; multibuf[5] = Netgame.team_vector; multibuf[6] = Bounty_target; multi_send_data(multibuf, 7, 2); } killed = Players[pnum].objnum; count += 1; killer = GET_INTEL_SHORT(buf + count); if (killer > 0) killer = objnum_remote_to_local(killer, (sbyte)buf[count+2]); if (!multi_i_am_master()) { Netgame.team_vector = buf[5]; Bounty_target = buf[6]; } multi_compute_kill(killer, killed); if (Game_mode & GM_BOUNTY && multi_i_am_master()) // update in case if needed... we could attach this to this packet but... meh... multi_send_bounty(); } // Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1 // which means not a controlcen object, but contained in another object void multi_do_controlcen_destroy(const ubyte *buf) { sbyte who; short objnum; objnum = GET_INTEL_SHORT(buf + 1); who = buf[3]; if (Control_center_destroyed != 1) { if ((who < N_players) && (who != Player_num)) { HUD_init_message(HM_MULTI, "%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL); } else if (who == Player_num) HUD_init_message_literal(HM_MULTI, TXT_YOU_DEST_CONTROL); else HUD_init_message_literal(HM_MULTI, TXT_CONTROL_DESTROYED); if (objnum != -1) net_destroy_controlcen(Objects+objnum); else net_destroy_controlcen(NULL); } } void multi_do_escape(const ubyte *buf) { int objnum; objnum = Players[(int)buf[1]].objnum; if (buf[2] == 0) { digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message(HM_MULTI, "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED); if (Game_mode & GM_NETWORK) Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL; if (!multi_goto_secret) multi_goto_secret = 2; } else if (buf[2] == 1) { digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message(HM_MULTI, "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET); if (Game_mode & GM_NETWORK) Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET; if (!multi_goto_secret) multi_goto_secret = 1; } create_player_appearance_effect(&Objects[objnum]); multi_make_player_ghost(buf[1]); } void multi_do_remobj(const ubyte *buf) { short objnum; // which object to remove short local_objnum; sbyte obj_owner; // which remote list is it entered in objnum = GET_INTEL_SHORT(buf + 1); obj_owner = buf[3]; Assert(objnum >= 0); if (objnum < 1) return; local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum if (local_objnum < 0) { return; } if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE)) { return; } if (Network_send_objects && multi_objnum_is_past(local_objnum)) { Network_send_objnum = -1; } if (Objects[local_objnum].type==OBJ_POWERUP) if (Game_mode & GM_NETWORK) { if (multi_powerup_is_4pack (Objects[local_objnum].id)) { if (PowerupsInMine[Objects[local_objnum].id-1]-4<0) PowerupsInMine[Objects[local_objnum].id-1]=0; else PowerupsInMine[Objects[local_objnum].id-1]-=4; } else { if (PowerupsInMine[Objects[local_objnum].id]>0) PowerupsInMine[Objects[local_objnum].id]--; } } Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless } void multi_disconnect_player(int pnum) { int i, n = 0; if (!(Game_mode & GM_NETWORK)) return; if (Players[pnum].connected == CONNECT_DISCONNECTED) return; if (Players[pnum].connected == CONNECT_PLAYING) { digi_play_sample( SOUND_HUD_MESSAGE, F1_0 ); HUD_init_message(HM_MULTI, "%s %s", Players[pnum].callsign, TXT_HAS_LEFT_THE_GAME); multi_sending_message[pnum] = 0; if (Network_status == NETSTAT_PLAYING) { multi_make_player_ghost(pnum); multi_strip_robots(pnum); } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_disconnect(pnum); // Bounty target left - select a new one if( Game_mode & GM_BOUNTY && pnum == Bounty_target && multi_i_am_master() ) { /* Select a random number */ int new = d_rand() % MAX_PLAYERS; /* Make sure they're valid: Don't check against kill flags, * just in case everyone's dead! */ while( !Players[new].connected ) new = d_rand() % MAX_PLAYERS; /* Select new target */ multi_new_bounty_target( new ); /* Send this new data */ multi_send_bounty(); } } Players[pnum].connected = CONNECT_DISCONNECTED; Netgame.players[pnum].connected = CONNECT_DISCONNECTED; PKilledFlags[pnum] = 1; switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_disconnect_player(pnum); break; #endif default: Error("Protocol handling missing in multi_disconnect_player\n"); break; } if (pnum == multi_who_is_master()) // Host has left - Quit game! { if (Network_status==NETSTAT_PLAYING) multi_leave_game(); if (Game_wind) window_set_visible(Game_wind, 0); nm_messagebox(NULL, 1, TXT_OK, "Host left the game!"); if (Game_wind) window_set_visible(Game_wind, 1); multi_quit_game = 1; game_leave_menus(); multi_reset_stuff(); return; } for (i = 0; i < N_players; i++) if (Players[i].connected) n++; if (n == 1) { HUD_init_message_literal(HM_MULTI, "You are the only person remaining in this netgame"); } } void multi_do_quit(const ubyte *buf) { if (!(Game_mode & GM_NETWORK)) return; multi_disconnect_player((int)buf[1]); } void multi_do_cloak(const ubyte *buf) { int pnum; pnum = buf[1]; Assert(pnum < N_players); Players[pnum].flags |= PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = GameTime64; ai_do_cloak_stuff(); if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(pnum); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_cloak(pnum); } void multi_do_decloak(const ubyte *buf) { int pnum; pnum = buf[1]; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_decloak(pnum); } void multi_do_door_open(const ubyte *buf) { int segnum; short side; segment *seg; wall *w; segnum = GET_INTEL_SHORT(buf + 1); side = buf[3]; if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5)) { Int3(); return; } seg = &Segments[segnum]; if (seg->sides[side].wall_num == -1) { //Opening door on illegal wall Int3(); return; } w = &Walls[seg->sides[side].wall_num]; if (w->type == WALL_BLASTABLE) { if (!(w->flags & WALL_BLASTED)) { wall_destroy(seg, side); } return; } else if (w->state != WALL_DOOR_OPENING) { wall_open_door(seg, side); } } void multi_do_create_explosion(const ubyte *buf) { int pnum; int count = 1; pnum = buf[count++]; create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1); } void multi_do_controlcen_fire(const ubyte *buf) { vms_vector to_target; int gun_num; short objnum; int count = 1; memcpy(&to_target, buf+count, 12); count += 12; #ifdef WORDS_BIGENDIAN // swap the vector to_target to_target.x = (fix)INTEL_INT((int)to_target.x); to_target.y = (fix)INTEL_INT((int)to_target.y); to_target.z = (fix)INTEL_INT((int)to_target.z); #endif gun_num = buf[count]; count += 1; objnum = GET_INTEL_SHORT(buf + count); count += 2; Laser_create_new_easy(&to_target, &Objects[objnum].ctype.reactor_info.gun_pos[gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1); } void multi_do_create_powerup(const ubyte *buf) { short segnum; short objnum; int my_objnum; int pnum; int count = 1; vms_vector new_pos; char powerup_type; if (Endlevel_sequence || Control_center_destroyed) return; pnum = buf[count++]; powerup_type = buf[count++]; segnum = GET_INTEL_SHORT(buf + count); count += 2; objnum = GET_INTEL_SHORT(buf + count); count += 2; if ((segnum < 0) || (segnum > Highest_segment_index)) { Int3(); return; } new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector); #ifdef WORDS_BIGENDIAN new_pos.x = (fix)SWAPINT((int)new_pos.x); new_pos.y = (fix)SWAPINT((int)new_pos.y); new_pos.z = (fix)SWAPINT((int)new_pos.z); #endif Net_create_loc = 0; my_objnum = call_object_create_egg(&Objects[Players[pnum].objnum], 1, OBJ_POWERUP, powerup_type); if (my_objnum < 0) { return; } if (Network_send_objects && multi_objnum_is_past(my_objnum)) { Network_send_objnum = -1; } Objects[my_objnum].pos = new_pos; vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity); obj_relink(my_objnum, segnum); map_objnum_local_to_remote(my_objnum, objnum, pnum); object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE); if (Game_mode & GM_NETWORK) { if (multi_powerup_is_4pack((int)powerup_type)) PowerupsInMine[(int)(powerup_type-1)]+=4; else PowerupsInMine[(int)powerup_type]++; } } void multi_do_play_sound(const ubyte *buf) { int pnum = buf[1]; int sound_num = buf[2]; fix volume = buf[3] << 12; if (!Players[pnum].connected) return; Assert(Players[pnum].objnum >= 0); Assert(Players[pnum].objnum <= Highest_object_index); digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume); } void multi_do_score(const ubyte *buf) { int pnum = buf[1]; if ((pnum < 0) || (pnum >= N_players)) { Int3(); // Non-terminal, see rob return; } if (Newdemo_state == ND_STATE_RECORDING) { int score; score = GET_INTEL_INT(buf + 2); newdemo_record_multi_score(pnum, score); } Players[pnum].score = GET_INTEL_INT(buf + 2); multi_sort_kill_list(); } void multi_do_trigger(const ubyte *buf) { int pnum = buf[1]; int trigger = buf[2]; if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num)) { Int3(); // Got trigger from illegal playernum return; } if ((trigger < 0) || (trigger >= Num_triggers)) { Int3(); // Illegal trigger number in multiplayer return; } check_trigger_sub(trigger, pnum, 0); } void multi_do_hostage_door_status(const ubyte *buf) { // Update hit point status of a door int count = 1; int wallnum; fix hps; wallnum = GET_INTEL_SHORT(buf + count); count += 2; hps = GET_INTEL_INT(buf + count); count += 4; if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE)) { Int3(); // Non-terminal, see Rob return; } if (hps < Walls[wallnum].hps) wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps); } void multi_reset_stuff(void) { // A generic, emergency function to solve problems that crop up // when a player exits quick-out from the game because of a // connection loss. Fixes several weird bugs! dead_player_end(); Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound. reset_rear_view(); } void multi_reset_player_object(object *objp) { int i; //Init physics for a non-console player Assert(objp >= Objects); Assert(objp <= Objects+Highest_object_index); Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST)); vm_vec_zero(&objp->mtype.phys_info.velocity); vm_vec_zero(&objp->mtype.phys_info.thrust); vm_vec_zero(&objp->mtype.phys_info.rotvel); vm_vec_zero(&objp->mtype.phys_info.rotthrust); objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0; objp->mtype.phys_info.mass = Player_ship->mass; objp->mtype.phys_info.drag = Player_ship->drag; if (objp->type == OBJ_PLAYER) objp->mtype.phys_info.flags |= PF_TURNROLL | PF_WIGGLE; else objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE); //Init render info objp->render_type = RT_POLYOBJ; objp->rtype.pobj_info.model_num = Player_ship->model_num; //what model is this? objp->rtype.pobj_info.subobj_flags = 0; //zero the flags for (i=0;irtype.pobj_info.anim_angles[i]); //reset textures for this, if not player 0 multi_reset_object_texture (objp); // Clear misc objp->flags = 0; if (objp->type == OBJ_GHOST) objp->render_type = RT_NONE; } void multi_reset_object_texture (object *objp) { int id,i; if (Game_mode & GM_TEAM) id = get_team(objp->id); else id = objp->id; if (id == 0) objp->rtype.pobj_info.alt_textures=0; else { if (N_PLAYER_SHIP_TEXTURES < Polygon_models[objp->rtype.pobj_info.model_num].n_textures) Error("Too many player ship textures!\n"); for (i=0;irtype.pobj_info.model_num].n_textures;i++) multi_player_textures[id-1][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[objp->rtype.pobj_info.model_num].first_texture+i]]; multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]]; multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]]; objp->rtype.pobj_info.alt_textures = id; } } void multi_process_bigdata(const ubyte *buf, unsigned len) { // Takes a bunch of messages, check them for validity, // and pass them to multi_process_data. unsigned type, sub_len, bytes_processed = 0; while( bytes_processed < len ) { type = buf[bytes_processed]; if ( (type>= sizeof(message_length)/sizeof(message_length[0]))) { con_printf( CON_DEBUG,"multi_process_bigdata: Invalid packet type %d!\n", type ); return; } sub_len = message_length[type]; Assert(sub_len > 0); if ( (bytes_processed+sub_len) > len ) { con_printf(CON_DEBUG, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len ); Int3(); return; } multi_process_data(&buf[bytes_processed], sub_len); bytes_processed += sub_len; } } // // Part 2 : Functions that send communication messages to inform the other // players of something we did. // void multi_send_fire(int laser_gun, int laser_level, int laser_flags, int laser_fired, short laser_track) { multi_do_protocol_frame(1, 0); // provoke positional update if possible multibuf[0] = (char)MULTI_FIRE; multibuf[1] = (char)Player_num; multibuf[2] = (char)laser_gun; multibuf[3] = (char)laser_level; multibuf[4] = (char)laser_flags; multibuf[5] = (char)laser_fired; PUT_INTEL_SHORT(multibuf+6, laser_track); multi_send_data(multibuf, 8, 1); } void multi_send_destroy_controlcen(int objnum, int player) { if (player == Player_num) HUD_init_message_literal(HM_MULTI, TXT_YOU_DEST_CONTROL); else if ((player > 0) && (player < N_players)) HUD_init_message(HM_MULTI, "%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL); else HUD_init_message_literal(HM_MULTI, TXT_CONTROL_DESTROYED); multibuf[0] = (char)MULTI_CONTROLCEN; PUT_INTEL_SHORT(multibuf+1, objnum); multibuf[3] = player; multi_send_data(multibuf, 4, 2); } void multi_send_endlevel_start(int secret) { multibuf[0] = (char)MULTI_ENDLEVEL_START; multibuf[1] = Player_num; multibuf[2] = (char)secret; if ((secret) && !multi_goto_secret) multi_goto_secret = 1; else if (!multi_goto_secret) multi_goto_secret = 2; multi_send_data(multibuf, 3, 2); if (Game_mode & GM_NETWORK) { Players[Player_num].connected = CONNECT_ESCAPE_TUNNEL; switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: net_udp_send_endlevel_packet(); break; #endif default: Error("Protocol handling missing in multi_send_endlevel_start\n"); break; } } } void multi_send_player_explode(char type) { int count = 0; int i; Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) ); if (Network_send_objects) { Network_send_objnum = -1; } multi_send_position(Players[Player_num].objnum); multibuf[count++] = type; multibuf[count++] = Player_num; multibuf[count++] = (char)Players[Player_num].primary_weapon_flags; multibuf[count++] = (char)Players[Player_num].secondary_weapon_flags; multibuf[count++] = (char)Players[Player_num].laser_level; multibuf[count++] = (char)Players[Player_num].secondary_ammo[HOMING_INDEX]; multibuf[count++] = (char)Players[Player_num].secondary_ammo[CONCUSSION_INDEX]; multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_INDEX]; multibuf[count++] = (char)Players[Player_num].secondary_ammo[MEGA_INDEX]; multibuf[count++] = (char)Players[Player_num].secondary_ammo[PROXIMITY_INDEX]; PUT_INTEL_SHORT(multibuf+count, Players[Player_num].primary_ammo[VULCAN_INDEX] ); count += 2; PUT_INTEL_INT(multibuf+count, Players[Player_num].flags ); count += 4; multibuf[count++] = Net_create_loc; Assert(Net_create_loc <= MAX_NET_CREATE_OBJECTS); memset(multibuf+count, -1, MAX_NET_CREATE_OBJECTS*sizeof(short)); for (i = 0; i < Net_create_loc; i++) { if (Net_create_objnums[i] <= 0) { #if 0 // Now legal, happens if there are too much powerups in mine Int3(); // Illegal value in created egg object numbers #endif continue; } PUT_INTEL_SHORT(multibuf+count, Net_create_objnums[i]); count += 2; // We created these objs so our local number = the network number map_objnum_local_to_local((short)Net_create_objnums[i]); } Net_create_loc = 0; if (count > message_length[MULTI_PLAYER_EXPLODE]) { Int3(); // See Rob } multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) multi_send_decloak(); multi_strip_robots(Player_num); } extern int Proximity_dropped; /* * Powerup capping: Keep track of how many powerups are in level and kill these which would exceed initial limit. */ // Count the initial amount of Powerups in the level void multi_powcap_count_powerups_in_mine(void) { int i; for (i=0;i=MaxPowerupsAllowed[(int)type]) if(Players[Player_num].primary_weapon_flags & (1 << index)) { con_printf(CON_VERBOSE,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]); con_printf(CON_VERBOSE,"Killing a primary cuz there's too many! (%d)\n",type); Players[Player_num].primary_weapon_flags&=(~(1 << index)); } } Players[Player_num].secondary_ammo[2]/=4; for (index=0;indexMaxPowerupsAllowed[(int)type]) { if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0) Players[Player_num].secondary_ammo[index]=0; else Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]); con_printf(CON_VERBOSE,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]); } } Players[Player_num].secondary_ammo[2]*=4; if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE]) Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK]) Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED); } // Adds players inventory to multi cap void multi_powcap_adjust_cap_for_player(int pnum) { char type; int index; if (!(Game_mode & GM_NETWORK)) return; for (index=0;index -1) { short s = (short)objnum_local_to_remote(killer_objnum, (sbyte *)&multibuf[count+2]); // do it with variable since INTEL_SHORT won't work on return val from function. PUT_INTEL_SHORT(multibuf+count, s); } else { PUT_INTEL_SHORT(multibuf+count, -1); multibuf[count+2] = (char)-1; } count += 3; // I am host - I know what's going on so attach game_mode related info which might be vital for correct kill computation if (multi_i_am_master()) { multibuf[count] = Netgame.team_vector; count += 1; multibuf[count] = Bounty_target; count += 1; } if (multi_i_am_master()) { multi_compute_kill(killer_objnum, objnum); multi_send_data(multibuf, count, 2); } else multi_send_data_direct((ubyte*)multibuf, count, multi_who_is_master(), 2); // I am just a client so I'll only send my kill but not compute it, yet. I'll get response from host so I can compute it correctly if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(Player_num); if (Game_mode & GM_BOUNTY && multi_i_am_master()) // update in case if needed... we could attach this to this packet but... meh... multi_send_bounty(); } void multi_send_remobj(int objnum) { // Tell the other guy to remove an object from his list sbyte obj_owner; short remote_objnum; if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK)) { if (multi_powerup_is_4pack (Objects[objnum].id)) { if (PowerupsInMine[Objects[objnum].id-1]-4<0) PowerupsInMine[Objects[objnum].id-1]=0; else PowerupsInMine[Objects[objnum].id-1]-=4; } else { if (PowerupsInMine[Objects[objnum].id]>0) PowerupsInMine[Objects[objnum].id]--; } } multibuf[0] = (char)MULTI_REMOVE_OBJECT; remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner); PUT_INTEL_SHORT(multibuf+1, remote_objnum); // Map to network objnums multibuf[3] = obj_owner; multi_send_data(multibuf, 4, 2); if (Network_send_objects && multi_objnum_is_past(objnum)) { Network_send_objnum = -1; } } void multi_send_quit(int why) { // I am quitting the game, tell the other guy the bad news. Assert (why == MULTI_QUIT); multibuf[0] = (char)why; multibuf[1] = Player_num; multi_send_data(multibuf, 2, 2); } void multi_send_cloak(void) { // Broadcast a change in our pflags (made to support cloaking) multibuf[0] = MULTI_CLOAK; multibuf[1] = (char)Player_num; multi_send_data(multibuf, 2, 2); if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(Player_num); } void multi_send_decloak(void) { // Broadcast a change in our pflags (made to support cloaking) multibuf[0] = MULTI_DECLOAK; multibuf[1] = (char)Player_num; multi_send_data(multibuf, 2, 2); } void multi_send_door_open(int segnum, int side, ubyte flag) { (void)flag; multibuf[0] = MULTI_DOOR_OPEN; PUT_INTEL_SHORT(multibuf+1, segnum ); multibuf[3] = (sbyte)side; multi_send_data(multibuf, 4, 2); } // // Part 3 : Functions that change or prepare the game for multiplayer use. // Not including functions needed to syncronize or start the // particular type of multiplayer game. Includes preparing the // mines, player structures, etc. void multi_send_create_explosion(int pnum) { // Send all data needed to create a remote explosion int count = 0; multibuf[count] = MULTI_CREATE_EXPLOSION; count += 1; multibuf[count] = (sbyte)pnum; count += 1; // ----------- // Total size = 2 multi_send_data(multibuf, count, 0); } void multi_send_controlcen_fire(vms_vector *to_goal, int best_gun_num, int objnum) { #ifdef WORDS_BIGENDIAN vms_vector swapped_vec; #endif int count = 0; multibuf[count] = MULTI_CONTROLCEN_FIRE; count += 1; #ifndef WORDS_BIGENDIAN memcpy(multibuf+count, to_goal, 12); count += 12; #else swapped_vec.x = (fix)INTEL_INT( (int)to_goal->x ); swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y ); swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z ); memcpy(multibuf+count, &swapped_vec, 12); count += 12; #endif multibuf[count] = (char)best_gun_num; count += 1; PUT_INTEL_SHORT(multibuf+count, objnum ); count += 2; // ------------ // Total = 16 multi_send_data(multibuf, count, 0); } void multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos) { // Create a powerup on a remote machine, used for remote // placement of used powerups like missiles and cloaking // powerups. #ifdef WORDS_BIGENDIAN vms_vector swapped_vec; #endif int count = 0; multi_send_position(Players[Player_num].objnum); if (Game_mode & GM_NETWORK) { if (multi_powerup_is_4pack(powerup_type)) PowerupsInMine[powerup_type-1]+=4; else PowerupsInMine[powerup_type]++; } multibuf[count] = MULTI_CREATE_POWERUP; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = powerup_type; count += 1; PUT_INTEL_SHORT(multibuf+count, segnum ); count += 2; PUT_INTEL_SHORT(multibuf+count, objnum ); count += 2; #ifndef WORDS_BIGENDIAN memcpy(multibuf+count, pos, sizeof(vms_vector)); count += sizeof(vms_vector); #else swapped_vec.x = (fix)INTEL_INT( (int)pos->x ); swapped_vec.y = (fix)INTEL_INT( (int)pos->y ); swapped_vec.z = (fix)INTEL_INT( (int)pos->z ); memcpy(multibuf+count, &swapped_vec, 12); count += 12; #endif // ----------- // Total = 19 multi_send_data(multibuf, count, 2); if (Network_send_objects && multi_objnum_is_past(objnum)) { Network_send_objnum = -1; } map_objnum_local_to_local(objnum); } void multi_send_play_sound(int sound_num, fix volume) { int count = 0; multibuf[count] = MULTI_PLAY_SOUND; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = (char)sound_num; count += 1; multibuf[count] = (char)(volume >> 12); count += 1; // ----------- // Total = 4 multi_send_data(multibuf, count, 0); } void multi_send_audio_taunt(int taunt_num) { #ifdef AUDIO_TAUNTS int audio_taunts[4] = { // Begin addition by GF SOUND_CONTROL_CENTER_WARNING_SIREN, SOUND_HOMING_WARNING, SOUND_CONTROL_CENTER_DESTROYED, SOUND_MINE_BLEW_UP // End addition by GF }; Assert(taunt_num >= 0); Assert(taunt_num < 4); digi_play_sample( audio_taunts[taunt_num], F1_0 ); multi_send_play_sound(audio_taunts[taunt_num], F1_0); #endif } void multi_send_score(void) { // Send my current score to all other players so it will remain // synced. int count = 0; if (Game_mode & GM_MULTI_COOP) { multi_sort_kill_list(); multibuf[count] = MULTI_SCORE; count += 1; multibuf[count] = Player_num; count += 1; PUT_INTEL_INT(multibuf+count, Players[Player_num].score); count += 4; multi_send_data(multibuf, count, 0); } } void multi_send_trigger(int triggernum) { // Send an event to trigger something in the mine int count = 0; multibuf[count] = MULTI_TRIGGER; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = (ubyte)triggernum; count += 1; multi_send_data(multibuf, count, 2); } void multi_send_hostage_door_status(int wallnum) { // Tell the other player what the hit point status of a hostage door // should be int count = 0; Assert(Walls[wallnum].type == WALL_BLASTABLE); multibuf[count] = MULTI_HOSTAGE_DOOR; count += 1; PUT_INTEL_SHORT(multibuf+count, wallnum ); count += 2; PUT_INTEL_INT(multibuf+count, Walls[wallnum].hps ); count += 4; multi_send_data(multibuf, count, 0); } void multi_consistency_error(int reset) { static int count = 0; if (reset) count = 0; if (++count < 10) return; if (Game_wind) window_set_visible(Game_wind, 0); nm_messagebox(NULL, 1, TXT_OK, TXT_CONSISTENCY_ERROR); if (Game_wind) window_set_visible(Game_wind, 1); count = 0; multi_quit_game = 1; game_leave_menus(); multi_reset_stuff(); } void multi_prep_level(void) { // Do any special stuff to the level required for games // before we begin playing in it. // Player_num MUST be set before calling this procedure. // This function must be called before checksuming the Object array, // since the resulting checksum with depend on the value of Player_num // at the time this is called. int i; int cloak_count, inv_count; Assert(Game_mode & GM_MULTI); Assert(NumNetPlayerPositions > 0); Bounty_target = 0; multi_consistency_error(1); for (i=0;i= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD)) { Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } if (Objects[i].id == POW_INVULNERABILITY) { if (inv_count >= 3 || (!(Netgame.AllowedItems & NETFLAG_DOINVUL))) { Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } else inv_count++; } if (Objects[i].id == POW_CLOAK) { if (cloak_count >= 3 || (!(Netgame.AllowedItems & NETFLAG_DOCLOAK))) { Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } else cloak_count++; } if (Objects[i].id == POW_FUSION_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOFUSION)) bash_to_shield (i,"fusion"); if (Objects[i].id == POW_MEGA_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOMEGA)) bash_to_shield (i,"mega"); if (Objects[i].id == POW_SMARTBOMB_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOSMART)) bash_to_shield (i,"smartmissile"); if (Objects[i].id == POW_VULCAN_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOVULCAN)) bash_to_shield (i,"vulcan"); if (Objects[i].id == POW_PLASMA_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOPLASMA)) bash_to_shield (i,"plasma"); if (Objects[i].id == POW_PROXIMITY_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOPROXIM)) bash_to_shield (i,"proximity"); if (Objects[i].id==POW_VULCAN_AMMO && (!(Netgame.AllowedItems & NETFLAG_DOVULCAN))) bash_to_shield(i,"vulcan ammo"); if (Objects[i].id == POW_SPREADFIRE_WEAPON && !(Netgame.AllowedItems & NETFLAG_DOSPREAD)) bash_to_shield (i,"spread"); if (Objects[i].id == POW_LASER && !(Netgame.AllowedItems & NETFLAG_DOLASER)) bash_to_shield (i,"Laser powerup"); if (Objects[i].id == POW_HOMING_AMMO_1 && !(Netgame.AllowedItems & NETFLAG_DOHOMING)) bash_to_shield (i,"Homing"); if (Objects[i].id == POW_HOMING_AMMO_4 && !(Netgame.AllowedItems & NETFLAG_DOHOMING)) bash_to_shield (i,"Homing"); if (Objects[i].id == POW_QUAD_FIRE && !(Netgame.AllowedItems & NETFLAG_DOQUAD)) bash_to_shield (i,"Quad Lasers"); } } multi_sort_kill_list(); multi_show_player_list(); ConsoleObject->control_type = CT_FLYING; reset_player_object(); imulti_new_game=0; } int multi_level_sync(void) { switch (multi_protocol) { #ifdef USE_UDP case MULTI_PROTO_UDP: return net_udp_level_sync(); break; #endif default: Error("Protocol handling missing in multi_level_sync\n"); break; } } void multi_set_robot_ai(void) { // Go through the objects array looking for robots and setting // them to certain supported types of NET AI behavior. // int i; // // for (i = 0; i <= Highest_object_index; i++) // { // if (Objects[i].type == OBJ_ROBOT) { // Objects[i].ai_info.REMOTE_OWNER = -1; // if (Objects[i].ai_info.behavior == AIB_STATION) // Objects[i].ai_info.behavior = AIB_NORMAL; // } // } } int multi_delete_extra_objects() { int i; int nnp=0; object *objp; // Go through the object list and remove any objects not used in // 'Anarchy!' games. // This function also prints the total number of available multiplayer // positions in this level, even though this should always be 8 or more! objp = Objects; for (i=0;i<=Highest_object_index;i++) { if ((objp->type==OBJ_PLAYER) || (objp->type==OBJ_GHOST)) nnp++; else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS)) ; else if ( (objp->type!=OBJ_NONE) && (objp->type!=OBJ_PLAYER) && (objp->type!=OBJ_POWERUP) && (objp->type!=OBJ_CNTRLCEN) && (objp->type!=OBJ_HOSTAGE) ) obj_delete(i); objp++; } return nnp; } // Returns 1 if player is Master/Host of this game int multi_i_am_master(void) { return (Player_num == 0); } // Returns the Player_num of Master/Host of this game int multi_who_is_master(void) { return 0; } void change_playernum_to( int new_Player_num ) { // if (Player_num > -1) // memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 ); if (Player_num > -1) { char *buf; MALLOC(buf,char,CALLSIGN_LEN+1); memcpy( buf, Players[Player_num].callsign, CALLSIGN_LEN+1 ); strcpy(Players[new_Player_num].callsign,buf); d_free(buf); } Player_num = new_Player_num; } int multi_all_players_alive() { int i; for (i=0;iMaxPowerupsAllowed[i]) MaxPowerupsAllowed[i]=buf[i+1]; } #define POWERUPADJUSTS 2 int PowerupAdjustMapping[]={11,19}; int multi_powerup_is_4pack (int id) { int i; for (i=0;ibest) { best=Players[i].KillGoalCount; bestnum=i; } } if (bestnum==Player_num) { HUD_init_message(HM_MULTI, "You have the best score at %d kills!",best); //Players[Player_num].shields=i2f(200); } else HUD_init_message(HM_MULTI, "%s has the best score with %d kills!",Players[bestnum].callsign,best); HUD_init_message_literal(HM_MULTI, "The control center has been destroyed!"); objp=obj_find_first_of_type (OBJ_CNTRLCEN); net_destroy_controlcen (objp); } extern char *RankStrings[]; void multi_add_lifetime_kills () { // This function adds a kill to lifetime stats of this player, and possibly // gives a promotion. If so, it will tell everyone else int oldrank; if (!(Game_mode & GM_NETWORK)) return; oldrank=GetMyNetRanking(); PlayerCfg.NetlifeKills++; if (oldrank!=GetMyNetRanking()) { multi_send_ranking(); if (!PlayerCfg.NoRankings) { HUD_init_message(HM_MULTI, "You have been promoted to %s!",RankStrings[GetMyNetRanking()]); digi_play_sample (SOUND_CONTROL_CENTER_WARNING_SIREN,F1_0*2); Netgame.players[Player_num].rank=GetMyNetRanking(); } } } void multi_add_lifetime_killed () { // This function adds a "killed" to lifetime stats of this player, and possibly // gives a demotion. If so, it will tell everyone else int oldrank; if (!(Game_mode & GM_NETWORK)) return; oldrank=GetMyNetRanking(); PlayerCfg.NetlifeKilled++; if (oldrank!=GetMyNetRanking()) { multi_send_ranking(); Netgame.players[Player_num].rank=GetMyNetRanking(); if (!PlayerCfg.NoRankings) HUD_init_message(HM_MULTI, "You have been demoted to %s!",RankStrings[GetMyNetRanking()]); } } void multi_send_ranking () { multibuf[0]=(char)MULTI_RANK; multibuf[1]=(char)Player_num; multibuf[2]=(char)GetMyNetRanking(); multi_send_data (multibuf,3,2); } void multi_do_ranking (char *buf) { char rankstr[20]; char pnum=buf[1]; char rank=buf[2]; if (Netgame.players[(int)pnum].rankrank) strcpy (rankstr,"demoted"); else return; Netgame.players[(int)pnum].rank=rank; if (!PlayerCfg.NoRankings) HUD_init_message(HM_MULTI, "%s has been %s to %s!",Players[(int)pnum].callsign,rankstr,RankStrings[(int)rank]); } // Decide if fire from "killer" is friendly. If yes return 1 (no harm to me) otherwise 0 (damage me) int multi_maybe_disable_friendly_fire(object *killer) { if (!(Game_mode & GM_NETWORK)) // no Multiplayer game -> always harm me! return 0; if (!Netgame.NoFriendlyFire) // friendly fire is activated -> harm me! return 0; if (killer == NULL) // no actual killer -> harm me! return 0; if (killer->type != OBJ_PLAYER) // not a player -> harm me! return 0; if (Game_mode & GM_MULTI_COOP) // coop mode -> don't harm me! return 1; else if (Game_mode & GM_TEAM) // team mode - find out if killer is in my team { if (get_team(Player_num) == get_team(killer->id)) // in my team -> don't harm me! return 1; else // opposite team -> harm me! return 0; } return 0; // all other cases -> harm me! } /* Bounty packer sender and handler */ void multi_send_bounty( void ) { /* Test game mode */ if( !( Game_mode & GM_BOUNTY ) ) return; if ( !multi_i_am_master() ) return; /* Add opcode, target ID and how often we re-assigned */ multibuf[0] = MULTI_DO_BOUNTY; multibuf[1] = (char)Bounty_target; /* Send data */ multi_send_data( multibuf, 2, 2 ); } void multi_do_bounty( const ubyte *buf ) { if ( multi_i_am_master() ) return; multi_new_bounty_target( buf[1] ); } void multi_new_bounty_target( int pnum ) { /* If it's already the same, don't do it */ if( Bounty_target == pnum ) return; /* Set the target */ Bounty_target = pnum; /* Send a message */ HUD_init_message( HM_MULTI, "%c%c%s is the new target!", CC_COLOR, BM_XRGB( player_rgb[Bounty_target].r, player_rgb[Bounty_target].g, player_rgb[Bounty_target].b ), Players[Bounty_target].callsign ); digi_play_sample( SOUND_CONTROL_CENTER_WARNING_SIREN, F1_0 * 3 ); } void multi_do_save_game(const ubyte *buf) { int count = 1; ubyte slot; uint id; char desc[25]; slot = *(ubyte *)(buf+count); count += 1; id = GET_INTEL_INT(buf+count); count += 4; memcpy( desc, &buf[count], 20 ); count += 20; multi_save_game( slot, id, desc ); } void multi_do_restore_game(const ubyte *buf) { int count = 1; ubyte slot; uint id; slot = *(ubyte *)(buf+count); count += 1; id = GET_INTEL_INT(buf+count); count += 4; multi_restore_game( slot, id ); } void multi_send_save_game(ubyte slot, uint id, char * desc) { int count = 0; multibuf[count] = MULTI_SAVE_GAME; count += 1; multibuf[count] = slot; count += 1; // Save slot=0 PUT_INTEL_INT( multibuf+count, id ); count += 4; // Save id memcpy( &multibuf[count], desc, 20 ); count += 20; multi_send_data(multibuf, count, 2); } void multi_send_restore_game(ubyte slot, uint id) { int count = 0; multibuf[count] = MULTI_RESTORE_GAME; count += 1; multibuf[count] = slot; count += 1; // Save slot=0 PUT_INTEL_INT( multibuf+count, id ); count += 4; // Save id multi_send_data(multibuf, count, 2); } void multi_initiate_save_game() { fix game_id = 0; int i, j, slot; char filename[PATH_MAX]; char desc[24]; if ((Endlevel_sequence) || (Control_center_destroyed)) return; if (!multi_i_am_master()) { HUD_init_message_literal(HM_MULTI, "Only host is allowed to save a game!"); return; } if (!multi_all_players_alive()) { HUD_init_message_literal(HM_MULTI, "Can't save! All players must be alive!"); return; } for (i = 0; i < N_players; i++) { for (j = 0; j < N_players; j++) { if (i != j && !d_stricmp(Players[i].callsign, Players[j].callsign)) { HUD_init_message_literal(HM_MULTI, "Can't save! Multiple players with same callsign!"); return; } } } memset(&filename, '\0', PATH_MAX); memset(&desc, '\0', 24); slot = state_get_save_file(filename, desc, 0 ); if (!slot) return; slot--; // Make a unique game id game_id = ((fix)timer_query()); game_id ^= N_players<<4; for (i = 0; i < N_players; i++ ) { fix call2i; memcpy(&call2i, Players[i].callsign, sizeof(fix)); game_id ^= call2i; } if ( game_id == 0 ) game_id = 1; // 0 is invalid multi_send_save_game( slot, game_id, desc ); multi_do_frame(); multi_save_game( slot,game_id, desc ); } extern int state_get_game_id(char *); void multi_initiate_restore_game() { int i, j, slot; char filename[PATH_MAX]; if ((Endlevel_sequence) || (Control_center_destroyed)) return; if (!multi_i_am_master()) { HUD_init_message_literal(HM_MULTI, "Only host is allowed to load a game!"); return; } if (!multi_all_players_alive()) { HUD_init_message_literal(HM_MULTI, "Can't load! All players must be alive!"); return; } for (i = 0; i < N_players; i++) { for (j = 0; j < N_players; j++) { if (i != j && !d_stricmp(Players[i].callsign, Players[j].callsign)) { HUD_init_message_literal(HM_MULTI, "Can't load! Multiple players with same callsign!"); return; } } } slot = state_get_restore_file(filename); if (!slot) return; state_game_id = state_get_game_id(filename); if (!state_game_id) return; slot--; multi_send_restore_game(slot,state_game_id); multi_do_frame(); multi_restore_game(slot,state_game_id); } void multi_save_game(ubyte slot, uint id, char *desc) { char filename[PATH_MAX]; if ((Endlevel_sequence) || (Control_center_destroyed)) return; snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%s.mg%d" : "%s.mg%d", Players[Player_num].callsign, slot); HUD_init_message(HM_MULTI, "Saving game #%d, '%s'", slot, desc); stop_time(); state_game_id = id; state_save_all_sub(filename, desc ); } void multi_restore_game(ubyte slot, uint id) { char filename[PATH_MAX]; int i; int thisid; if ((Endlevel_sequence) || (Control_center_destroyed)) return; snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%s.mg%d" : "%s.mg%d", Players[Player_num].callsign, slot); for (i = 0; i < N_players; i++) multi_strip_robots(i); if (multi_i_am_master()) // put all players to wait-state again so we can sync up properly for (i = 0; i < MAX_PLAYERS; i++) if (Players[i].connected == CONNECT_PLAYING && i != Player_num) Players[i].connected = CONNECT_WAITING; thisid=state_get_game_id(filename); if (thisid!=id) { nm_messagebox(NULL, 1, TXT_OK, "A multi-save game was restored\nthat you are missing or does not\nmatch that of the others.\nYou must rejoin if you wish to\ncontinue."); return; } state_restore_all_sub( filename ); multi_send_score(); // send my restored scores. I sent 0 when I loaded the level anyways... } void multi_do_msgsend_state(const ubyte *buf) { multi_sending_message[(int)buf[1]] = (int)buf[2]; } void multi_send_msgsend_state(int state) { multibuf[0] = (char)MULTI_TYPING_STATE; multibuf[1] = Player_num; multibuf[2] = (char)state; multi_send_data(multibuf, 3, 2); } // Specific variables related to our game mode we want the clients to know about void multi_send_gmode_update() { if (!multi_i_am_master()) return; if (!(Game_mode & GM_TEAM || Game_mode & GM_BOUNTY)) // expand if necessary return; multibuf[0] = (char)MULTI_GMODE_UPDATE; multibuf[1] = Netgame.team_vector; multibuf[2] = Bounty_target; multi_send_data(multibuf, 3, 0); } void multi_do_gmode_update(const ubyte *buf) { if (multi_i_am_master()) return; if (Game_mode & GM_TEAM) { if (buf[1] != Netgame.team_vector) { int t; Netgame.team_vector = buf[1]; for (t=0;t= sizeof(message_length) / sizeof(message_length[0])) { Int3(); return; } switch(type) { case MULTI_POSITION: if (!Endlevel_sequence) multi_do_position(buf); break; case MULTI_REAPPEAR: if (!Endlevel_sequence) multi_do_reappear(buf); break; case MULTI_FIRE: if (!Endlevel_sequence) multi_do_fire(buf); break; case MULTI_KILL: multi_do_kill(buf); break; case MULTI_REMOVE_OBJECT: if (!Endlevel_sequence) multi_do_remobj(buf); break; case MULTI_PLAYER_DROP: case MULTI_PLAYER_EXPLODE: if (!Endlevel_sequence) multi_do_player_explode(buf); break; case MULTI_MESSAGE: if (!Endlevel_sequence) multi_do_message(buf); break; case MULTI_QUIT: if (!Endlevel_sequence) multi_do_quit(buf); break; case MULTI_BEGIN_SYNC: break; case MULTI_CONTROLCEN: if (!Endlevel_sequence) multi_do_controlcen_destroy(buf); break; case MULTI_ENDLEVEL_START: if (!Endlevel_sequence) multi_do_escape(buf); break; case MULTI_END_SYNC: break; case MULTI_CLOAK: if (!Endlevel_sequence) multi_do_cloak(buf); break; case MULTI_DECLOAK: if (!Endlevel_sequence) multi_do_decloak(buf); break; case MULTI_DOOR_OPEN: if (!Endlevel_sequence) multi_do_door_open(buf); break; case MULTI_CREATE_EXPLOSION: if (!Endlevel_sequence) multi_do_create_explosion(buf); break; case MULTI_CONTROLCEN_FIRE: if (!Endlevel_sequence) multi_do_controlcen_fire(buf); break; case MULTI_CREATE_POWERUP: if (!Endlevel_sequence) multi_do_create_powerup(buf); break; case MULTI_PLAY_SOUND: if (!Endlevel_sequence) multi_do_play_sound(buf); break; case MULTI_ROBOT_CLAIM: if (!Endlevel_sequence) multi_do_claim_robot(buf); break; case MULTI_ROBOT_POSITION: if (!Endlevel_sequence) multi_do_robot_position(buf); break; case MULTI_ROBOT_EXPLODE: if (!Endlevel_sequence) multi_do_robot_explode(buf); break; case MULTI_ROBOT_RELEASE: if (!Endlevel_sequence) multi_do_release_robot(buf); break; case MULTI_ROBOT_FIRE: if (!Endlevel_sequence) multi_do_robot_fire(buf); break; case MULTI_SCORE: if (!Endlevel_sequence) multi_do_score(buf); break; case MULTI_CREATE_ROBOT: if (!Endlevel_sequence) multi_do_create_robot(buf); break; case MULTI_TRIGGER: if (!Endlevel_sequence) multi_do_trigger(buf); break; case MULTI_BOSS_ACTIONS: if (!Endlevel_sequence) multi_do_boss_actions(buf); break; case MULTI_CREATE_ROBOT_POWERUPS: if (!Endlevel_sequence) multi_do_create_robot_powerups(buf); break; case MULTI_HOSTAGE_DOOR: if (!Endlevel_sequence) multi_do_hostage_door_status(buf); break; case MULTI_SAVE_GAME: if (!Endlevel_sequence) multi_do_save_game(buf); break; case MULTI_RESTORE_GAME: if (!Endlevel_sequence) multi_do_restore_game(buf); break; case MULTI_POWCAP_UPDATE: if (!Endlevel_sequence) multi_do_powcap_update(buf); break; case MULTI_HEARTBEAT: if (!Endlevel_sequence) multi_do_heartbeat (buf); break; case MULTI_KILLGOALS: if (!Endlevel_sequence) multi_do_kill_goal_counts (buf); break; case MULTI_DO_BOUNTY: if( !Endlevel_sequence ) multi_do_bounty( buf ); break; case MULTI_TYPING_STATE: multi_do_msgsend_state( buf ); break; case MULTI_GMODE_UPDATE: multi_do_gmode_update( buf ); break; case MULTI_KILL_HOST: multi_do_kill(buf); break; case MULTI_KILL_CLIENT: multi_do_kill(buf); break; default: Int3(); } } // Following functions convert object to object_rw and back. // turn object to object_rw for sending void multi_object_to_object_rw(object *obj, object_rw *obj_rw) { obj_rw->signature = obj->signature; obj_rw->type = obj->type; obj_rw->id = obj->id; obj_rw->next = obj->next; obj_rw->prev = obj->prev; obj_rw->control_type = obj->control_type; obj_rw->movement_type = obj->movement_type; obj_rw->render_type = obj->render_type; obj_rw->flags = obj->flags; obj_rw->segnum = obj->segnum; obj_rw->attached_obj = obj->attached_obj; obj_rw->pos.x = obj->pos.x; obj_rw->pos.y = obj->pos.y; obj_rw->pos.z = obj->pos.z; obj_rw->orient.rvec.x = obj->orient.rvec.x; obj_rw->orient.rvec.y = obj->orient.rvec.y; obj_rw->orient.rvec.z = obj->orient.rvec.z; obj_rw->orient.fvec.x = obj->orient.fvec.x; obj_rw->orient.fvec.y = obj->orient.fvec.y; obj_rw->orient.fvec.z = obj->orient.fvec.z; obj_rw->orient.uvec.x = obj->orient.uvec.x; obj_rw->orient.uvec.y = obj->orient.uvec.y; obj_rw->orient.uvec.z = obj->orient.uvec.z; obj_rw->size = obj->size; obj_rw->shields = obj->shields; obj_rw->last_pos.x = obj->last_pos.x; obj_rw->last_pos.y = obj->last_pos.y; obj_rw->last_pos.z = obj->last_pos.z; obj_rw->contains_type = obj->contains_type; obj_rw->contains_id = obj->contains_id; obj_rw->contains_count= obj->contains_count; obj_rw->matcen_creator= obj->matcen_creator; obj_rw->lifeleft = obj->lifeleft; switch (obj_rw->movement_type) { case MT_PHYSICS: obj_rw->mtype.phys_info.velocity.x = obj->mtype.phys_info.velocity.x; obj_rw->mtype.phys_info.velocity.y = obj->mtype.phys_info.velocity.y; obj_rw->mtype.phys_info.velocity.z = obj->mtype.phys_info.velocity.z; obj_rw->mtype.phys_info.thrust.x = obj->mtype.phys_info.thrust.x; obj_rw->mtype.phys_info.thrust.y = obj->mtype.phys_info.thrust.y; obj_rw->mtype.phys_info.thrust.z = obj->mtype.phys_info.thrust.z; obj_rw->mtype.phys_info.mass = obj->mtype.phys_info.mass; obj_rw->mtype.phys_info.drag = obj->mtype.phys_info.drag; obj_rw->mtype.phys_info.brakes = obj->mtype.phys_info.brakes; obj_rw->mtype.phys_info.rotvel.x = obj->mtype.phys_info.rotvel.x; obj_rw->mtype.phys_info.rotvel.y = obj->mtype.phys_info.rotvel.y; obj_rw->mtype.phys_info.rotvel.z = obj->mtype.phys_info.rotvel.z; obj_rw->mtype.phys_info.rotthrust.x = obj->mtype.phys_info.rotthrust.x; obj_rw->mtype.phys_info.rotthrust.y = obj->mtype.phys_info.rotthrust.y; obj_rw->mtype.phys_info.rotthrust.z = obj->mtype.phys_info.rotthrust.z; obj_rw->mtype.phys_info.turnroll = obj->mtype.phys_info.turnroll; obj_rw->mtype.phys_info.flags = obj->mtype.phys_info.flags; break; case MT_SPINNING: obj_rw->mtype.spin_rate.x = obj->mtype.spin_rate.x; obj_rw->mtype.spin_rate.y = obj->mtype.spin_rate.y; obj_rw->mtype.spin_rate.z = obj->mtype.spin_rate.z; break; } switch (obj_rw->control_type) { case CT_WEAPON: obj_rw->ctype.laser_info.parent_type = obj->ctype.laser_info.parent_type; obj_rw->ctype.laser_info.parent_num = obj->ctype.laser_info.parent_num; obj_rw->ctype.laser_info.parent_signature = obj->ctype.laser_info.parent_signature; if (obj->ctype.laser_info.creation_time - GameTime64 < F1_0*(-18000)) obj_rw->ctype.laser_info.creation_time = F1_0*(-18000); else obj_rw->ctype.laser_info.creation_time = obj->ctype.laser_info.creation_time - GameTime64; obj_rw->ctype.laser_info.last_hitobj = obj->ctype.laser_info.last_hitobj; obj_rw->ctype.laser_info.track_goal = obj->ctype.laser_info.track_goal; obj_rw->ctype.laser_info.multiplier = obj->ctype.laser_info.multiplier; break; case CT_EXPLOSION: obj_rw->ctype.expl_info.spawn_time = obj->ctype.expl_info.spawn_time; obj_rw->ctype.expl_info.delete_time = obj->ctype.expl_info.delete_time; obj_rw->ctype.expl_info.delete_objnum = obj->ctype.expl_info.delete_objnum; obj_rw->ctype.expl_info.attach_parent = obj->ctype.expl_info.attach_parent; obj_rw->ctype.expl_info.prev_attach = obj->ctype.expl_info.prev_attach; obj_rw->ctype.expl_info.next_attach = obj->ctype.expl_info.next_attach; break; case CT_AI: { int i; obj_rw->ctype.ai_info.behavior = obj->ctype.ai_info.behavior; for (i = 0; i < MAX_AI_FLAGS; i++) obj_rw->ctype.ai_info.flags[i] = obj->ctype.ai_info.flags[i]; obj_rw->ctype.ai_info.hide_segment = obj->ctype.ai_info.hide_segment; obj_rw->ctype.ai_info.hide_index = obj->ctype.ai_info.hide_index; obj_rw->ctype.ai_info.path_length = obj->ctype.ai_info.path_length; obj_rw->ctype.ai_info.cur_path_index = obj->ctype.ai_info.cur_path_index; obj_rw->ctype.ai_info.follow_path_start_seg = obj->ctype.ai_info.follow_path_start_seg; obj_rw->ctype.ai_info.follow_path_end_seg = obj->ctype.ai_info.follow_path_end_seg; obj_rw->ctype.ai_info.danger_laser_signature = obj->ctype.ai_info.danger_laser_signature; obj_rw->ctype.ai_info.danger_laser_num = obj->ctype.ai_info.danger_laser_num; break; } case CT_LIGHT: obj_rw->ctype.light_info.intensity = obj->ctype.light_info.intensity; break; case CT_POWERUP: obj_rw->ctype.powerup_info.count = obj->ctype.powerup_info.count; break; } switch (obj_rw->render_type) { case RT_MORPH: case RT_POLYOBJ: case RT_NONE: // HACK below { int i; if (obj->render_type == RT_NONE && obj->type != OBJ_GHOST) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. break; obj_rw->rtype.pobj_info.model_num = obj->rtype.pobj_info.model_num; for (i=0;irtype.pobj_info.anim_angles[i].p = obj->rtype.pobj_info.anim_angles[i].p; obj_rw->rtype.pobj_info.anim_angles[i].b = obj->rtype.pobj_info.anim_angles[i].b; obj_rw->rtype.pobj_info.anim_angles[i].h = obj->rtype.pobj_info.anim_angles[i].h; } obj_rw->rtype.pobj_info.subobj_flags = obj->rtype.pobj_info.subobj_flags; obj_rw->rtype.pobj_info.tmap_override = obj->rtype.pobj_info.tmap_override; obj_rw->rtype.pobj_info.alt_textures = obj->rtype.pobj_info.alt_textures; break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj_rw->rtype.vclip_info.vclip_num = obj->rtype.vclip_info.vclip_num; obj_rw->rtype.vclip_info.frametime = obj->rtype.vclip_info.frametime; obj_rw->rtype.vclip_info.framenum = obj->rtype.vclip_info.framenum; break; case RT_LASER: break; } } // turn object_rw to object after receiving void multi_object_rw_to_object(object_rw *obj_rw, object *obj) { obj->signature = obj_rw->signature; obj->type = obj_rw->type; obj->id = obj_rw->id; obj->next = obj_rw->next; obj->prev = obj_rw->prev; obj->control_type = obj_rw->control_type; obj->movement_type = obj_rw->movement_type; obj->render_type = obj_rw->render_type; obj->flags = obj_rw->flags; obj->segnum = obj_rw->segnum; obj->attached_obj = obj_rw->attached_obj; obj->pos.x = obj_rw->pos.x; obj->pos.y = obj_rw->pos.y; obj->pos.z = obj_rw->pos.z; obj->orient.rvec.x = obj_rw->orient.rvec.x; obj->orient.rvec.y = obj_rw->orient.rvec.y; obj->orient.rvec.z = obj_rw->orient.rvec.z; obj->orient.fvec.x = obj_rw->orient.fvec.x; obj->orient.fvec.y = obj_rw->orient.fvec.y; obj->orient.fvec.z = obj_rw->orient.fvec.z; obj->orient.uvec.x = obj_rw->orient.uvec.x; obj->orient.uvec.y = obj_rw->orient.uvec.y; obj->orient.uvec.z = obj_rw->orient.uvec.z; obj->size = obj_rw->size; obj->shields = obj_rw->shields; obj->last_pos.x = obj_rw->last_pos.x; obj->last_pos.y = obj_rw->last_pos.y; obj->last_pos.z = obj_rw->last_pos.z; obj->contains_type = obj_rw->contains_type; obj->contains_id = obj_rw->contains_id; obj->contains_count= obj_rw->contains_count; obj->matcen_creator= obj_rw->matcen_creator; obj->lifeleft = obj_rw->lifeleft; switch (obj->movement_type) { case MT_PHYSICS: obj->mtype.phys_info.velocity.x = obj_rw->mtype.phys_info.velocity.x; obj->mtype.phys_info.velocity.y = obj_rw->mtype.phys_info.velocity.y; obj->mtype.phys_info.velocity.z = obj_rw->mtype.phys_info.velocity.z; obj->mtype.phys_info.thrust.x = obj_rw->mtype.phys_info.thrust.x; obj->mtype.phys_info.thrust.y = obj_rw->mtype.phys_info.thrust.y; obj->mtype.phys_info.thrust.z = obj_rw->mtype.phys_info.thrust.z; obj->mtype.phys_info.mass = obj_rw->mtype.phys_info.mass; obj->mtype.phys_info.drag = obj_rw->mtype.phys_info.drag; obj->mtype.phys_info.brakes = obj_rw->mtype.phys_info.brakes; obj->mtype.phys_info.rotvel.x = obj_rw->mtype.phys_info.rotvel.x; obj->mtype.phys_info.rotvel.y = obj_rw->mtype.phys_info.rotvel.y; obj->mtype.phys_info.rotvel.z = obj_rw->mtype.phys_info.rotvel.z; obj->mtype.phys_info.rotthrust.x = obj_rw->mtype.phys_info.rotthrust.x; obj->mtype.phys_info.rotthrust.y = obj_rw->mtype.phys_info.rotthrust.y; obj->mtype.phys_info.rotthrust.z = obj_rw->mtype.phys_info.rotthrust.z; obj->mtype.phys_info.turnroll = obj_rw->mtype.phys_info.turnroll; obj->mtype.phys_info.flags = obj_rw->mtype.phys_info.flags; break; case MT_SPINNING: obj->mtype.spin_rate.x = obj_rw->mtype.spin_rate.x; obj->mtype.spin_rate.y = obj_rw->mtype.spin_rate.y; obj->mtype.spin_rate.z = obj_rw->mtype.spin_rate.z; break; } switch (obj->control_type) { case CT_WEAPON: obj->ctype.laser_info.parent_type = obj_rw->ctype.laser_info.parent_type; obj->ctype.laser_info.parent_num = obj_rw->ctype.laser_info.parent_num; obj->ctype.laser_info.parent_signature = obj_rw->ctype.laser_info.parent_signature; obj->ctype.laser_info.creation_time = obj_rw->ctype.laser_info.creation_time; obj->ctype.laser_info.last_hitobj = obj_rw->ctype.laser_info.last_hitobj; obj->ctype.laser_info.track_goal = obj_rw->ctype.laser_info.track_goal; obj->ctype.laser_info.multiplier = obj_rw->ctype.laser_info.multiplier; break; case CT_EXPLOSION: obj->ctype.expl_info.spawn_time = obj_rw->ctype.expl_info.spawn_time; obj->ctype.expl_info.delete_time = obj_rw->ctype.expl_info.delete_time; obj->ctype.expl_info.delete_objnum = obj_rw->ctype.expl_info.delete_objnum; obj->ctype.expl_info.attach_parent = obj_rw->ctype.expl_info.attach_parent; obj->ctype.expl_info.prev_attach = obj_rw->ctype.expl_info.prev_attach; obj->ctype.expl_info.next_attach = obj_rw->ctype.expl_info.next_attach; break; case CT_AI: { int i; obj->ctype.ai_info.behavior = obj_rw->ctype.ai_info.behavior; for (i = 0; i < MAX_AI_FLAGS; i++) obj->ctype.ai_info.flags[i] = obj_rw->ctype.ai_info.flags[i]; obj->ctype.ai_info.hide_segment = obj_rw->ctype.ai_info.hide_segment; obj->ctype.ai_info.hide_index = obj_rw->ctype.ai_info.hide_index; obj->ctype.ai_info.path_length = obj_rw->ctype.ai_info.path_length; obj->ctype.ai_info.cur_path_index = obj_rw->ctype.ai_info.cur_path_index; obj->ctype.ai_info.follow_path_start_seg = obj_rw->ctype.ai_info.follow_path_start_seg; obj->ctype.ai_info.follow_path_end_seg = obj_rw->ctype.ai_info.follow_path_end_seg; obj->ctype.ai_info.danger_laser_signature = obj_rw->ctype.ai_info.danger_laser_signature; obj->ctype.ai_info.danger_laser_num = obj_rw->ctype.ai_info.danger_laser_num; break; } case CT_LIGHT: obj->ctype.light_info.intensity = obj_rw->ctype.light_info.intensity; break; case CT_POWERUP: obj->ctype.powerup_info.count = obj_rw->ctype.powerup_info.count; break; case CT_CNTRLCEN: { // gun points of reactor now part of the object but of course not saved in object_rw. Let's just recompute them. int i = 0; reactor *reactor = get_reactor_definition(obj->id); for (i=0; in_guns; i++) calc_controlcen_gun_point(reactor, obj, i); break; } } switch (obj->render_type) { case RT_MORPH: case RT_POLYOBJ: case RT_NONE: // HACK below { int i; if (obj->render_type == RT_NONE && obj->type != OBJ_GHOST) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. break; obj->rtype.pobj_info.model_num = obj_rw->rtype.pobj_info.model_num; for (i=0;irtype.pobj_info.anim_angles[i].p = obj_rw->rtype.pobj_info.anim_angles[i].p; obj->rtype.pobj_info.anim_angles[i].b = obj_rw->rtype.pobj_info.anim_angles[i].b; obj->rtype.pobj_info.anim_angles[i].h = obj_rw->rtype.pobj_info.anim_angles[i].h; } obj->rtype.pobj_info.subobj_flags = obj_rw->rtype.pobj_info.subobj_flags; obj->rtype.pobj_info.tmap_override = obj_rw->rtype.pobj_info.tmap_override; obj->rtype.pobj_info.alt_textures = obj_rw->rtype.pobj_info.alt_textures; break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj->rtype.vclip_info.vclip_num = obj_rw->rtype.vclip_info.vclip_num; obj->rtype.vclip_info.frametime = obj_rw->rtype.vclip_info.frametime; obj->rtype.vclip_info.framenum = obj_rw->rtype.vclip_info.framenum; break; case RT_LASER: break; } } dxx-rebirth-0.58.1-d1x/main/multi.h000066400000000000000000000345421217717257200170110ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Defines and exported variables for multi.c * */ #ifndef _MULTI_H #define _MULTI_H #include "gameseq.h" #include "piggy.h" #include "powerup.h" #include "newmenu.h" // Need these for non network builds too -Chris #define MAX_MESSAGE_LEN 35 #ifdef USE_UDP #ifdef _WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x0501 // for get/freeaddrinfo() #include #include #include #else #include #include #include #include #include #include #include #endif #ifdef IPv6 #define _sockaddr sockaddr_in6 #define _af AF_INET6 #define _pf PF_INET6 #else #define _sockaddr sockaddr_in #define _af AF_INET #define _pf PF_INET #endif #endif // PROTOCOL VARIABLES AND DEFINES extern int multi_protocol; // set and determinate used protocol #define MULTI_PROTO_UDP 1 // UDP protocol // What version of the multiplayer protocol is this? Increment each time something drastic changes in Multiplayer without the version number changes. Can be reset to 0 each time the version of the game changes #define MULTI_PROTO_VERSION 0 // PROTOCOL VARIABLES AND DEFINES - END #define define_multiplayer_command(NAME,SIZE) NAME, #define for_each_multiplayer_command(BEFORE,VALUE,AFTER) \ BEFORE \ VALUE(MULTI_POSITION , 25) \ VALUE(MULTI_REAPPEAR , 4) \ VALUE(MULTI_FIRE , 8) \ VALUE(MULTI_KILL , 5) \ VALUE(MULTI_REMOVE_OBJECT , 4) \ VALUE(MULTI_MESSAGE , 37) /* (MAX_MESSAGE_LENGTH = 40) */ \ VALUE(MULTI_QUIT , 2) \ VALUE(MULTI_PLAY_SOUND , 4) \ VALUE(MULTI_CONTROLCEN , 4) \ VALUE(MULTI_ROBOT_CLAIM , 5) \ VALUE(MULTI_END_SYNC , 4) \ VALUE(MULTI_CLOAK , 2) \ VALUE(MULTI_ENDLEVEL_START , 3) \ VALUE(MULTI_CREATE_EXPLOSION , 2) \ VALUE(MULTI_CONTROLCEN_FIRE , 16) \ VALUE(MULTI_CREATE_POWERUP , 19) \ VALUE(MULTI_DECLOAK , 2) \ VALUE(MULTI_MENU_CHOICE , 2) \ VALUE(MULTI_ROBOT_POSITION , 5+sizeof(shortpos)) \ VALUE(MULTI_PLAYER_EXPLODE , 57) \ VALUE(MULTI_BEGIN_SYNC , 37) \ VALUE(MULTI_DOOR_OPEN , 4) \ VALUE(MULTI_PLAYER_DROP , 57) \ VALUE(MULTI_ROBOT_EXPLODE , 8) \ VALUE(MULTI_ROBOT_RELEASE , 5) \ VALUE(MULTI_ROBOT_FIRE , 18) \ VALUE(MULTI_SCORE , 6) \ VALUE(MULTI_CREATE_ROBOT , 6) \ VALUE(MULTI_TRIGGER , 3) \ VALUE(MULTI_BOSS_ACTIONS , 10) \ VALUE(MULTI_CREATE_ROBOT_POWERUPS, 27) \ VALUE(MULTI_HOSTAGE_DOOR , 7) \ VALUE(MULTI_SAVE_GAME , 2+24) /* (ubyte slot, uint id, char name[20]) */ \ VALUE(MULTI_RESTORE_GAME , 2+4) /* (ubyte slot, uint id) */ \ VALUE(MULTI_HEARTBEAT , 5) \ VALUE(MULTI_KILLGOALS , 9) \ VALUE(MULTI_POWCAP_UPDATE , MAX_POWERUP_TYPES+1) \ VALUE(MULTI_DO_BOUNTY , 2) \ VALUE(MULTI_TYPING_STATE , 3) \ VALUE(MULTI_GMODE_UPDATE , 3) \ VALUE(MULTI_KILL_HOST , 7) \ VALUE(MULTI_KILL_CLIENT , 5) \ VALUE(MULTI_RANK , 3) \ AFTER for_each_multiplayer_command(enum {, define_multiplayer_command, }); #define MAX_MULTI_MESSAGE_LEN 90 //didn't change it, just moved it up #define MAX_NET_CREATE_OBJECTS 20 #define MISSILE_ADJUST 6 #define NETGAME_ANARCHY 0 #define NETGAME_TEAM_ANARCHY 1 #define NETGAME_ROBOT_ANARCHY 2 #define NETGAME_COOPERATIVE 3 #define NETGAME_BOUNTY 7 #define NETSTAT_MENU 0 #define NETSTAT_PLAYING 1 #define NETSTAT_BROWSING 2 #define NETSTAT_WAITING 3 #define NETSTAT_STARTING 4 #define NETSTAT_ENDLEVEL 5 #define CONNECT_DISCONNECTED 0 #define CONNECT_PLAYING 1 #define CONNECT_WAITING 2 #define CONNECT_DIED_IN_MINE 3 #define CONNECT_FOUND_SECRET 4 #define CONNECT_ESCAPE_TUNNEL 5 #define CONNECT_END_MENU 6 // reasons for a packet with type PID_DUMP #define DUMP_CLOSED 0 // no new players allowed after game started #define DUMP_FULL 1 // player cound maxed out #define DUMP_ENDLEVEL 2 #define DUMP_DORK 3 #define DUMP_ABORTED 4 #define DUMP_CONNECTED 5 // never used #define DUMP_LEVEL 6 #define DUMP_KICKED 7 #define DUMP_PKTTIMEOUT 8 #define for_each_netflag_value(VALUE) \ VALUE(NETFLAG_DOLASER, "Laser upgrade") \ VALUE(NETFLAG_DOQUAD, "Quad lasers") \ VALUE(NETFLAG_DOVULCAN, "Vulcan cannon") \ VALUE(NETFLAG_DOSPREAD, "Spreadfire cannon") \ VALUE(NETFLAG_DOPLASMA, "Plasma cannon") \ VALUE(NETFLAG_DOFUSION, "Fusion cannon") \ VALUE(NETFLAG_DOHOMING, "Homing missiles") \ VALUE(NETFLAG_DOPROXIM, "Proximity bombs") \ VALUE(NETFLAG_DOSMART, "Smart missiles") \ VALUE(NETFLAG_DOMEGA, "Mega missiles") \ VALUE(NETFLAG_DOCLOAK, "Cloaking") \ VALUE(NETFLAG_DOINVUL, "Invulnerability") \ #define define_netflag_bit_enum(NAME,STR) BIT_##NAME, #define define_netflag_bit_mask(NAME,STR) NAME = (1 << BIT_##NAME), #define define_netflag_powerup_mask(NAME,STR) | (NAME) enum { for_each_netflag_value(define_netflag_bit_enum) }; // Bitmask for netgame_info->AllowedItems to set allowed items in Netgame enum { for_each_netflag_value(define_netflag_bit_mask) }; enum { NETFLAG_DOPOWERUP = 0 for_each_netflag_value(define_netflag_powerup_mask) }; #define MULTI_GAME_TYPE_COUNT 8 #define MULTI_GAME_NAME_LENGTH 13 #define MULTI_ALLOW_POWERUP_MAX 12 int multi_allow_powerup_mask[MAX_POWERUP_TYPES]; extern char *multi_allow_powerup_text[MULTI_ALLOW_POWERUP_MAX]; extern const char GMNames[MULTI_GAME_TYPE_COUNT][MULTI_GAME_NAME_LENGTH]; extern const char GMNamesShrt[MULTI_GAME_TYPE_COUNT][8]; // Exported functions extern int GetMyNetRanking(); extern void ClipRank (ubyte *rank); int objnum_remote_to_local(int remote_obj, int owner); int objnum_local_to_remote(int local_obj, sbyte *owner); void map_objnum_local_to_remote(int local, int remote, int owner); void map_objnum_local_to_local(int objnum); void reset_network_objects(); int multi_objnum_is_past(int objnum); void multi_do_ping_frame(); void multi_init_objects(void); void multi_show_player_list(void); void multi_do_protocol_frame(int force, int listen); void multi_do_frame(void); void multi_send_fire(int laser_gun, int laser_level, int laser_flags, int laser_fired, short laser_track); void multi_send_destroy_controlcen(int objnum, int player); void multi_send_endlevel_start(int); void multi_send_player_explode(char type); void multi_send_message(void); void multi_send_position(int objnum); void multi_send_reappear(); void multi_send_kill(int objnum); void multi_send_remobj(int objnum); void multi_send_quit(int why); void multi_send_door_open(int segnum, int side,ubyte flag); void multi_send_create_explosion(int player_num); void multi_send_controlcen_fire(vms_vector *to_target, int gun_num, int objnum); void multi_send_cloak(void); void multi_send_decloak(void); void multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos); void multi_send_play_sound(int sound_num, fix volume); void multi_send_audio_taunt(int taunt_num); void multi_send_score(void); void multi_send_trigger(int trigger); void multi_send_hostage_door_status(int wallnum); void multi_send_bounty( void ); void multi_endlevel_score(void); void multi_consistency_error(int reset); void multi_prep_level(void); int multi_level_sync(void); int multi_endlevel(int *secret); int multi_endlevel_poll1(newmenu *menu, d_event *event, void *userdata); int multi_endlevel_poll2( newmenu *menu, d_event *event, void *userdata ); void multi_send_endlevel_packet(); void multi_leave_game(void); void multi_process_data(const ubyte *dat, int len); void multi_process_bigdata(const ubyte *buf, unsigned len); void multi_do_death(int objnum); void multi_send_message_dialog(void); int multi_delete_extra_objects(void); void multi_make_ghost_player(int objnum); void multi_make_player_ghost(int objnum); void multi_reset_player_object(object *objp); void multi_define_macro(int key); void multi_send_macro(int key); int multi_get_kill_list(int *plist); void multi_new_game(void); void multi_sort_kill_list(void); void multi_reset_stuff(void); void multi_send_data(unsigned char *buf, int len, int priority); int get_team(int pnum); int multi_maybe_disable_friendly_fire(object *killer); void multi_initiate_save_game(); void multi_initiate_restore_game(); void multi_disconnect_player(int pnum); void multi_object_to_object_rw(object *obj, object_rw *obj_rw); void multi_object_rw_to_object(object_rw *obj_rw, object *obj); // Exported variables extern int Network_status; // IMPORTANT: These variables needed for player rejoining done by protocol-specific code extern int Network_send_objects; extern int Network_send_object_mode; extern int Network_send_objnum; extern int Network_rejoined; extern int Network_sending_extras; extern int VerifyPlayerJoined; extern int Player_joining_extras; extern int Network_player_added; extern ubyte multibuf[MAX_MULTI_MESSAGE_LEN+4]; extern int who_killed_controlcen; extern int Net_create_objnums[MAX_NET_CREATE_OBJECTS]; extern int Net_create_loc; extern short kill_matrix[MAX_PLAYERS][MAX_PLAYERS]; extern short team_kills[2]; extern int multi_goto_secret; extern ushort my_segments_checksum; //do we draw the kill list on the HUD? extern int Show_kill_list; extern int Show_reticle_name; extern fix Show_kill_list_timer; // Used to send network messages extern char Network_message[MAX_MESSAGE_LEN]; extern int Network_message_reciever; // Used to map network to local object numbers extern short remote_to_local[MAX_PLAYERS][MAX_OBJECTS]; // Network object num for each extern short local_to_remote[MAX_OBJECTS]; // Local object num for each network objnum extern sbyte object_owner[MAX_OBJECTS]; // Who 'owns' each local object for network purposes extern int multi_quit_game; extern int multi_sending_message[MAX_PLAYERS]; extern int multi_defining_message; extern int multi_message_input_sub(int key); extern void multi_send_message_start(); extern int multi_powerup_is_4pack(int); extern void multi_message_feedback(); extern int Bounty_target; extern bitmap_index multi_player_textures[MAX_PLAYERS][N_PLAYER_SHIP_TEXTURES]; extern char *RankStrings[]; #define NETGAME_FLAG_CLOSED 1 #define NETGAME_FLAG_SHOW_ID 2 #define NETGAME_FLAG_SHOW_MAP 4 #define NETGAME_NAME_LEN 15 #define NETPLAYER_ORIG_SIZE 22 #define NETPLAYER_D1X_SIZE 22 /* D1X version removes last char from callsign */ int multi_i_am_master(void); int multi_who_is_master(void); void change_playernum_to(int new_pnum); // Multiplayer powerup capping extern void multi_powcap_count_powerups_in_mine(void); extern void multi_powcap_cap_objects(); extern void multi_do_powcap_update(); extern void multi_send_powcap_update(); extern void multi_send_kill_goal_counts(); // Globals for protocol-bound Refuse-functions extern char RefuseThisPlayer,WaitForRefuseAnswer,RefuseTeam,RefusePlayerName[12]; extern fix64 RefuseTimeLimit; #define REFUSE_INTERVAL (F1_0*8) extern struct netgame_info Netgame; /* * The Network Players structure * Contains protocol-specific data with designated prefixes and general player-related data. * Note that not all of these infos will be sent to other users - some are used and/or set locally, only. */ typedef struct netplayer_info { #if defined(USE_UDP) union { #ifdef USE_UDP struct { struct _sockaddr addr; // IP address of this peer ubyte isyou; // This flag is set true while sending info to tell player his designated (re)join position } udp; #endif } protocol; #endif char callsign[CALLSIGN_LEN+1]; sbyte connected; ubyte rank; fix ping; fix64 LastPacketTime; } __pack__ netplayer_info; /* * The Network Game structure * Contains protocol-specific data with designated prefixes and general game-related data. * Note that not all of these infos will be sent to clients - some are used and/or set locally, only. */ typedef struct netgame_info { #if defined(USE_UDP) union { #ifdef USE_UDP struct { struct _sockaddr addr; // IP address of this netgame's host short program_iver[4]; // IVER of program for version checking sbyte valid; // Status of Netgame info: -1 = Failed, Wrong version; 0 = No info, yet; 1 = Success fix GameID; } udp; #endif } protocol; #endif struct netplayer_info players[MAX_PLAYERS+4]; char game_name[NETGAME_NAME_LEN+1]; char mission_title[MISSION_NAME_LEN+1]; char mission_name[9]; int levelnum; ubyte gamemode; ubyte RefusePlayers; ubyte difficulty; ubyte game_status; ubyte numplayers; ubyte max_numplayers; ubyte numconnected; ubyte game_flags; ubyte team_vector; u_int32_t AllowedItems; short Allow_marker_view; // (unused in D1 - no markers in game) short AlwaysLighting; // (unused in D1 - cannot destroy lights after all) short ShowEnemyNames; short BrightPlayers; short InvulAppear; char team_name[2][CALLSIGN_LEN+1]; int locations[MAX_PLAYERS]; short kills[MAX_PLAYERS][MAX_PLAYERS]; ushort segments_checksum; short team_kills[2]; short killed[MAX_PLAYERS]; short player_kills[MAX_PLAYERS]; int KillGoal; fix PlayTimeAllowed; fix level_time; int control_invul_time; int monitor_vector; int player_score[MAX_PLAYERS]; ubyte player_flags[MAX_PLAYERS]; short PacketsPerSec; ubyte ShortPackets; ubyte PacketLossPrevention; ubyte NoFriendlyFire; #ifdef USE_TRACKER ubyte Tracker; #endif } __pack__ netgame_info; #endif /* _MULTI_H */ dxx-rebirth-0.58.1-d1x/main/multibot.c000066400000000000000000000752441217717257200175150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Multiplayer robot code * */ #ifdef NETWORK #ifndef SHAREWARE #include #include #include "vecmat.h" #include "game.h" #include "multi.h" #include "object.h" #include "laser.h" #include "dxxerror.h" #include "timer.h" #include "text.h" #include "ai.h" #include "fireball.h" #include "aistruct.h" #include "robot.h" #include "powerup.h" #include "scores.h" #include "gauges.h" #include "fuelcen.h" #include "morph.h" #include "digi.h" #include "sounds.h" #include "effects.h" #include "physics.h" #include "multibot.h" #include "byteswap.h" void multi_delete_controlled_robot(int objnum); void multi_send_robot_position_sub(int objnum, int now); void multi_send_release_robot(int objnum); int multi_add_controlled_robot(int objnum, int agitation); // // Code for controlling robots in multiplayer games // #define STANDARD_EXPL_DELAY (F1_0/4) #define MIN_CONTROL_TIME F1_0*2 #define ROBOT_TIMEOUT F1_0*3 #define MIN_TO_ADD 60 #define MAX_TO_DELETE 67 int robot_controlled[MAX_ROBOTS_CONTROLLED]; int robot_agitation[MAX_ROBOTS_CONTROLLED]; fix64 robot_controlled_time[MAX_ROBOTS_CONTROLLED]; fix64 robot_last_send_time[MAX_ROBOTS_CONTROLLED]; fix64 robot_last_message_time[MAX_ROBOTS_CONTROLLED]; int robot_send_pending[MAX_ROBOTS_CONTROLLED]; int robot_fired[MAX_ROBOTS_CONTROLLED]; ubyte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3]; #define MULTI_ROBOT_PRIORITY(objnum, pnum) (((objnum % 4) + pnum) % N_players) //#define MULTI_ROBOT_PRIORITY(objnum, pnum) multi_robot_priority(objnum, pnum) //int multi_robot_priority(int objnum, int pnum) //{ // return( ((objnum % 4) + pnum) % N_players); //} int multi_can_move_robot(int objnum, int agitation) { // Determine whether or not I am allowed to move this robot. int rval; // Claim robot if necessary. if (Player_exploded) return 0; #ifndef NDEBUG if ((objnum < 0) || (objnum > Highest_object_index)) { Int3(); rval = 0; } else if (Objects[objnum].type != OBJ_ROBOT) { Int3(); rval = 0; } #endif else if ((Robot_info[Objects[objnum].id].boss_flag) && (Boss_dying == 1)) return 0; else if (Objects[objnum].ctype.ai_info.REMOTE_OWNER == Player_num) // Already my robot! { int slot_num = Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM; Assert((slot_num > -1) && (slot_num < MAX_ROBOTS_CONTROLLED)); if (robot_fired[slot_num]) { rval = 0; } else { robot_agitation[slot_num] = agitation; robot_last_message_time[slot_num] = GameTime64; rval = 1; } } else if ((Objects[objnum].ctype.ai_info.REMOTE_OWNER != -1) || (agitation < MIN_TO_ADD)) { if (agitation == ROBOT_FIRE_AGITATION) // Special case for firing at non-player { rval = 1; // Try to fire at player even tho we're not in control! } else rval = 0; } else rval = multi_add_controlled_robot(objnum, agitation); return(rval); } void multi_check_robot_timeout(void) { static fix64 lastcheck = 0; int i; if (GameTime64 > lastcheck + F1_0 || lastcheck > GameTime64) { lastcheck = GameTime64; for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++) { if ((robot_controlled[i] != -1) && (robot_last_send_time[i] + ROBOT_TIMEOUT < GameTime64)) { if (Objects[robot_controlled[i]].ctype.ai_info.REMOTE_OWNER != Player_num) { robot_controlled[i] = -1; Int3(); // Non-terminal but Rob is interesting, step over please... return; } // Assert(Objects[robot_controlled[i]].ctype.ai_info.REMOTE_OWNER == Player_num); if (robot_send_pending[i]) multi_send_robot_position(robot_controlled[i], 1); multi_send_release_robot(robot_controlled[i]); // multi_delete_controlled_robot(robot_controlled[i]); // robot_controlled[i] = -1; } } } } void multi_strip_robots(int playernum) { // Grab all robots away from a player // (player died or exited the game) int i; if (Game_mode & GM_MULTI_ROBOTS) { if (playernum == Player_num) for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++) multi_delete_controlled_robot(robot_controlled[i]); for (i = 1; i <= Highest_object_index; i++) if ((Objects[i].type == OBJ_ROBOT) && (Objects[i].ctype.ai_info.REMOTE_OWNER == playernum)) { Assert((Objects[i].control_type == CT_AI) || (Objects[i].control_type == CT_NONE) || (Objects[i].control_type == CT_MORPH)); Objects[i].ctype.ai_info.REMOTE_OWNER = -1; if (playernum == Player_num) Objects[i].ctype.ai_info.REMOTE_SLOT_NUM = 4; else Objects[i].ctype.ai_info.REMOTE_SLOT_NUM = 0; } } // Note -- only call this with playernum == Player_num if all other players // already know that we are clearing house. This does not send a release // message for each controlled robot!! } void multi_dump_robots(void) { // Dump robot control info for debug purposes if (!(Game_mode & GM_MULTI_ROBOTS)) return; } int multi_add_controlled_robot(int objnum, int agitation) { int i; int lowest_agitation = 0x7fffffff; // MAX POSITIVE INT int lowest_agitated_bot = -1; int first_free_robot = -1; // Try to add a new robot to the controlled list, return 1 if added, 0 if not. if (Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM > 0) { Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM -= 1; return 0; } for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++) { if ((robot_controlled[i] == -1) || (Objects[robot_controlled[i]].type != OBJ_ROBOT)) { first_free_robot = i; break; } if (robot_last_message_time[i] + ROBOT_TIMEOUT < GameTime64) { if (robot_send_pending[i]) multi_send_robot_position(robot_controlled[i], 1); multi_send_release_robot(robot_controlled[i]); first_free_robot = i; break; } if ((robot_controlled[i] != -1) && (robot_agitation[i] < lowest_agitation) && (robot_controlled_time[i] + MIN_CONTROL_TIME < GameTime64)) { lowest_agitation = robot_agitation[i]; lowest_agitated_bot = i; } } if (first_free_robot != -1) // Room left for new robots i = first_free_robot; else if ((agitation > lowest_agitation) && (lowest_agitation <= MAX_TO_DELETE)) // Replace some old robot with a more agitated one { if (robot_send_pending[lowest_agitated_bot]) multi_send_robot_position(robot_controlled[lowest_agitated_bot], 1); multi_send_release_robot(robot_controlled[lowest_agitated_bot]); i = lowest_agitated_bot; } else { return(0); // Sorry, can't squeeze him in! } multi_send_claim_robot(objnum); robot_controlled[i] = objnum; robot_agitation[i] = agitation; Objects[objnum].ctype.ai_info.REMOTE_OWNER = Player_num; Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM = i; robot_controlled_time[i] = GameTime64; robot_last_send_time[i] = robot_last_message_time[i] = GameTime64; return(1); } void multi_delete_controlled_robot(int objnum) { int i; // Delete robot object number objnum from list of controlled robots because it is dead if ( (objnum<0) || (objnum>Highest_object_index)) { return; } for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++) if (robot_controlled[i] == objnum) break; if (i == MAX_ROBOTS_CONTROLLED) return; Assert(Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM == i); Objects[objnum].ctype.ai_info.REMOTE_OWNER = -1; Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM = 0; robot_controlled[i] = -1; robot_send_pending[i] = 0; robot_fired[i] = 0; } void multi_send_claim_robot(int objnum) { short s; if ((objnum < 0) || (objnum > Highest_object_index)) { Int3(); // See rob return; } if (Objects[objnum].type != OBJ_ROBOT) { Int3(); // See rob return; } // The AI tells us we should take control of this robot. multibuf[0] = (char)MULTI_ROBOT_CLAIM; multibuf[1] = Player_num; s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]); PUT_INTEL_SHORT(multibuf+2, s); multi_send_data(multibuf, 5, 2); } void multi_send_release_robot(int objnum) { short s; if ((objnum < 0) || (objnum > Highest_object_index)) { Int3(); // See rob return; } if (Objects[objnum].type != OBJ_ROBOT) { Int3(); // See rob return; } multi_delete_controlled_robot(objnum); multibuf[0] = (char)MULTI_ROBOT_RELEASE; multibuf[1] = Player_num; s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]); PUT_INTEL_SHORT(multibuf+2, s); multi_send_data(multibuf, 5, 2); } #define MIN_ROBOT_COM_GAP F1_0/12 int multi_send_robot_frame(int sent) { static int last_sent = 0; int i; int rval = 0; for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++) { int sending = (last_sent+1+i)%MAX_ROBOTS_CONTROLLED; if ( (robot_controlled[sending] != -1) && ((robot_send_pending[sending] > sent) || (robot_fired[sending] > sent)) ) { if (robot_send_pending[sending]) { multi_send_robot_position_sub(robot_controlled[sending], (robot_send_pending[sending]>1)?1:0); robot_send_pending[sending] = 0; } if (robot_fired[sending]) { robot_fired[sending] = 0; multi_send_data(robot_fire_buf[sending], 18, 1); } if (!(Game_mode & GM_NETWORK)) sent += 1; last_sent = sending; rval++; } } Assert((last_sent >= 0) && (last_sent <= MAX_ROBOTS_CONTROLLED)); return(rval); } void multi_send_robot_position_sub(int objnum, int now) { int loc = 0; short s; #ifdef WORDS_BIGENDIAN shortpos sp; #endif multibuf[loc] = MULTI_ROBOT_POSITION; loc += 1; multibuf[loc] = Player_num; loc += 1; s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[loc+2]); PUT_INTEL_SHORT(multibuf+loc, s); loc += 3; #ifndef WORDS_BIGENDIAN create_shortpos((shortpos *)(multibuf+loc), Objects+objnum,0); loc += sizeof(shortpos); #else create_shortpos(&sp, Objects+objnum, 1); memcpy(&(multibuf[loc]), (ubyte *)(sp.bytemat), 9); loc += 9; memcpy(&(multibuf[loc]), (ubyte *)&(sp.xo), 14); loc += 14; #endif multi_send_data(multibuf, loc, now?1:0); } void multi_send_robot_position(int objnum, int force) { // Send robot position to other player(s). Includes a byte // value describing whether or not they fired a weapon if (!(Game_mode & GM_MULTI)) return; if ((objnum < 0) || (objnum > Highest_object_index)) { Int3(); // See rob return; } if (Objects[objnum].type != OBJ_ROBOT) { Int3(); // See rob return; } if (Objects[objnum].ctype.ai_info.REMOTE_OWNER != Player_num) return; // Objects[objnum].phys_info.drag = Robot_info[Objects[objnum].id].drag; // Set drag to normal robot_last_send_time[Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM] = GameTime64; robot_send_pending[Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM] = 1+force; return; } void multi_send_robot_fire(int objnum, int gun_num, vms_vector *fire) { // Send robot fire event int loc = 0; short s; #ifdef WORDS_BIGENDIAN vms_vector swapped_vec; #endif multibuf[loc] = MULTI_ROBOT_FIRE; loc += 1; multibuf[loc] = Player_num; loc += 1; s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[loc+2]); PUT_INTEL_SHORT(multibuf+loc, s); loc += 3; multibuf[loc] = gun_num; loc += 1; #ifndef WORDS_BIGENDIAN memcpy(multibuf+loc, fire, sizeof(vms_vector)); loc += sizeof(vms_vector); // 12 // -------------------------- // Total = 18 #else swapped_vec.x = (fix)INTEL_INT((int)fire->x); swapped_vec.y = (fix)INTEL_INT((int)fire->y); swapped_vec.z = (fix)INTEL_INT((int)fire->z); memcpy(multibuf+loc, &swapped_vec, sizeof(vms_vector)); loc += sizeof(vms_vector); #endif if (Objects[objnum].ctype.ai_info.REMOTE_OWNER == Player_num) { int slot = Objects[objnum].ctype.ai_info.REMOTE_SLOT_NUM; Assert((slot >= 0) && (slot < MAX_ROBOTS_CONTROLLED)); if (robot_fired[slot] != 0) Int3(); // ROB! memcpy(robot_fire_buf[slot], multibuf, loc); robot_fired[slot] = 1; } else multi_send_data(multibuf, loc, 0); // Not our robot, send ASAP } void multi_send_robot_explode(int objnum, int killer,char isthief) { // Send robot explosion event to the other players int loc = 0; short s; multibuf[loc] = MULTI_ROBOT_EXPLODE; loc += 1; multibuf[loc] = Player_num; loc += 1; s = (short)objnum_local_to_remote(killer, (sbyte *)&multibuf[loc+2]); PUT_INTEL_SHORT(multibuf+loc, s); loc += 3; s = (short)objnum_local_to_remote(objnum, (sbyte *)&multibuf[loc+2]); PUT_INTEL_SHORT(multibuf+loc, s); loc += 3; (void)isthief; multi_send_data(multibuf, loc, 2); multi_delete_controlled_robot(objnum); } void multi_send_create_robot(int station, int objnum, int type) { // Send create robot information int loc = 0; multibuf[loc] = MULTI_CREATE_ROBOT; loc += 1; multibuf[loc] = Player_num; loc += 1; multibuf[loc] = (sbyte)station; loc += 1; PUT_INTEL_SHORT(multibuf+loc, objnum); loc += 2; multibuf[loc] = type; loc += 1; map_objnum_local_to_local((short)objnum); multi_send_data(multibuf, loc, 2); } void multi_send_boss_actions(int bossobjnum, int action, int secondary, int objnum) { // Send special boss behavior information int loc = 0; multibuf[loc] = MULTI_BOSS_ACTIONS; loc += 1; multibuf[loc] = Player_num; loc += 1; // Which player is controlling the boss PUT_INTEL_SHORT(multibuf+loc, bossobjnum); loc += 2; // We won't network map this objnum since it's the boss multibuf[loc] = (sbyte)action; loc += 1; // What is the boss doing? multibuf[loc] = (sbyte)secondary; loc += 1; // More info for what he is doing PUT_INTEL_SHORT(multibuf+loc, objnum); loc += 2; // Objnum of object created by gate-in action if (action == 3) { PUT_INTEL_SHORT(multibuf+loc, Objects[objnum].segnum); loc += 2; // Segment number object created in (for gate only) } else loc += 2; // Dummy if (action == 1) { // Teleport releases robot // Boss is up for grabs after teleporting Assert((Objects[bossobjnum].ctype.ai_info.REMOTE_SLOT_NUM >= 0) && (Objects[bossobjnum].ctype.ai_info.REMOTE_SLOT_NUM < MAX_ROBOTS_CONTROLLED)); multi_delete_controlled_robot(bossobjnum); // robot_controlled[Objects[bossobjnum].ctype.ai_info.REMOTE_SLOT_NUM] = -1; // Objects[bossobjnum].ctype.ai_info.REMOTE_OWNER = -1; Objects[bossobjnum].ctype.ai_info.REMOTE_SLOT_NUM = 5; // Hands-off period! } multi_send_data(multibuf, loc, 2); } #define MAX_ROBOT_POWERUPS 4 void multi_send_create_robot_powerups(object *del_obj) { // Send create robot information int loc = 0; int i; #ifdef WORDS_BIGENDIAN vms_vector swapped_vec; #endif multibuf[loc] = MULTI_CREATE_ROBOT_POWERUPS; loc += 1; multibuf[loc] = Player_num; loc += 1; multibuf[loc] = del_obj->contains_count; loc += 1; multibuf[loc] = del_obj->contains_type; loc += 1; multibuf[loc] = del_obj->contains_id; loc += 1; PUT_INTEL_SHORT(multibuf+loc, del_obj->segnum); loc += 2; #ifndef WORDS_BIGENDIAN memcpy(multibuf+loc, &del_obj->pos, sizeof(vms_vector)); loc += 12; #else swapped_vec.x = (fix)INTEL_INT((int)del_obj->pos.x); swapped_vec.y = (fix)INTEL_INT((int)del_obj->pos.y); swapped_vec.z = (fix)INTEL_INT((int)del_obj->pos.z); memcpy(multibuf+loc, &swapped_vec, sizeof(vms_vector)); loc += 12; #endif memset(multibuf+loc, -1, MAX_ROBOT_POWERUPS*sizeof(short)); if ((Net_create_loc > MAX_ROBOT_POWERUPS) || (Net_create_loc < 1)) { Int3(); // See Rob } for (i = 0; i < Net_create_loc; i++) { PUT_INTEL_SHORT(multibuf+loc, Net_create_objnums[i]); loc += 2; map_objnum_local_to_local(Net_create_objnums[i]); } Net_create_loc = 0; multi_send_data(multibuf, 27, 2); } void multi_do_claim_robot(const ubyte *buf) { short botnum; short remote_botnum; char pnum; pnum = buf[1]; remote_botnum = GET_INTEL_SHORT(buf + 2); botnum = objnum_remote_to_local(remote_botnum, (sbyte)buf[4]); if ((botnum > Highest_object_index) || (botnum < 0)) { return; } if (Objects[botnum].type != OBJ_ROBOT) { return; } if (Objects[botnum].ctype.ai_info.REMOTE_OWNER != -1) { if (MULTI_ROBOT_PRIORITY(remote_botnum, pnum) <= MULTI_ROBOT_PRIORITY(remote_botnum, Objects[botnum].ctype.ai_info.REMOTE_OWNER)) return; } // Perform the requested change if (Objects[botnum].ctype.ai_info.REMOTE_OWNER == Player_num) { multi_delete_controlled_robot(botnum); } Objects[botnum].ctype.ai_info.REMOTE_OWNER = pnum; Objects[botnum].ctype.ai_info.REMOTE_SLOT_NUM = 0; } void multi_do_release_robot(const ubyte *buf) { short botnum, remote_botnum; char pnum; pnum = buf[1]; remote_botnum = GET_INTEL_SHORT(buf + 2); botnum = objnum_remote_to_local(remote_botnum, (sbyte)buf[4]); if ((botnum < 0) || (botnum > Highest_object_index)) { return; } if (Objects[botnum].type != OBJ_ROBOT) { return; } if (Objects[botnum].ctype.ai_info.REMOTE_OWNER != pnum) { return; } // Perform the requested change Objects[botnum].ctype.ai_info.REMOTE_OWNER = -1; Objects[botnum].ctype.ai_info.REMOTE_SLOT_NUM = 0; } void multi_do_robot_position(const ubyte *buf) { // Process robot movement sent by another player short botnum, remote_botnum; char pnum; int loc = 1; #ifdef WORDS_BIGENDIAN shortpos sp; #endif pnum = buf[loc]; loc += 1; remote_botnum = GET_INTEL_SHORT(buf + loc); botnum = objnum_remote_to_local(remote_botnum, (sbyte)buf[loc+2]); loc += 3; if ((botnum < 0) || (botnum > Highest_object_index)) { return; } if ((Objects[botnum].type != OBJ_ROBOT) || (Objects[botnum].flags & OF_EXPLODING)) { return; } if (Objects[botnum].ctype.ai_info.REMOTE_OWNER != pnum) { if (Objects[botnum].ctype.ai_info.REMOTE_OWNER == -1) { // Robot claim packet must have gotten lost, let this player claim it. if (Objects[botnum].ctype.ai_info.REMOTE_SLOT_NUM > 3) { Objects[botnum].ctype.ai_info.REMOTE_OWNER = pnum; Objects[botnum].ctype.ai_info.REMOTE_SLOT_NUM = 0; } else Objects[botnum].ctype.ai_info.REMOTE_SLOT_NUM++; } else { return; } } set_thrust_from_velocity(&Objects[botnum]); // Try to smooth out movement // Objects[botnum].phys_info.drag = Robot_info[Objects[botnum].id].drag >> 4; // Set drag to low #ifndef WORDS_BIGENDIAN extract_shortpos(&Objects[botnum], (shortpos *)(buf+loc), 0); #else memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + loc), 9); loc += 9; memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + loc), 14); extract_shortpos(&Objects[botnum], &sp, 1); #endif } void multi_do_robot_fire(const ubyte *buf) { // Send robot fire event int loc = 1; int botnum; short remote_botnum; int gun_num; vms_vector fire, gun_point; robot_info *robptr; loc += 1; // pnum remote_botnum = GET_INTEL_SHORT(buf + loc); botnum = objnum_remote_to_local(remote_botnum, (sbyte)buf[loc+2]); loc += 3; gun_num = (sbyte)buf[loc]; loc += 1; memcpy(&fire, buf+loc, sizeof(vms_vector)); fire.x = (fix)INTEL_INT((int)fire.x); fire.y = (fix)INTEL_INT((int)fire.y); fire.z = (fix)INTEL_INT((int)fire.z); if ((botnum < 0) || (botnum > Highest_object_index) || (Objects[botnum].type != OBJ_ROBOT) || (Objects[botnum].flags & OF_EXPLODING)) { return; } // Do the firing if (gun_num == -1) { // Drop proximity bombs vm_vec_add(&gun_point, &Objects[botnum].pos, &fire); Laser_create_new_easy( &fire, &gun_point, botnum, PROXIMITY_ID, 1); } else { calc_gun_point(&gun_point, &Objects[botnum], gun_num); robptr = &Robot_info[Objects[botnum].id]; Laser_create_new_easy( &fire, &gun_point, botnum, robptr->weapon_type, 1); } } int multi_explode_robot_sub(int botnum, int killer,char isthief) { object *robot; killer = killer; if ((botnum < 0) || (botnum > Highest_object_index)) { // Objnum in range? Int3(); // See rob return 0; } if (Objects[botnum].type != OBJ_ROBOT) { // Object is robot? return 0; } if (Objects[botnum].flags & OF_EXPLODING) { // Object not already exploding return 0; } // Data seems valid, explode the sucker if (Network_send_objects && multi_objnum_is_past(botnum)) { Network_send_objnum = -1; } robot = &Objects[botnum]; // Drop non-random KEY powerups locally only! if ((robot->contains_count > 0) && (robot->contains_type == OBJ_POWERUP) && (Game_mode & GM_MULTI_COOP) && (robot->contains_id >= POW_KEY_BLUE) && (robot->contains_id <= POW_KEY_GOLD)) { object_create_egg(robot); } else if (robot->ctype.ai_info.REMOTE_OWNER == Player_num) { multi_drop_robot_powerups(robot-Objects); multi_delete_controlled_robot(robot-Objects); } else if (robot->ctype.ai_info.REMOTE_OWNER == -1 && multi_i_am_master()) { multi_drop_robot_powerups(robot-Objects); } (void)isthief; if (Robot_info[robot->id].boss_flag) { if (!Boss_dying) start_boss_death_sequence(robot); else return 0; } else explode_object(robot, STANDARD_EXPL_DELAY); return 1; } void multi_do_robot_explode(const ubyte *buf) { // Explode robot controlled by other player int botnum; short remote_botnum; int loc = 1; short killer, remote_killer; int rval; char thief; loc += 1; // pnum remote_killer = GET_INTEL_SHORT(buf + loc); killer = objnum_remote_to_local(remote_killer, (sbyte)buf[loc+2]); loc += 3; remote_botnum = GET_INTEL_SHORT(buf + loc); botnum = objnum_remote_to_local(remote_botnum, (sbyte)buf[loc+2]); loc += 3; thief = 0; if ((botnum < 0) || (botnum > Highest_object_index)) { return; } rval = multi_explode_robot_sub(botnum, killer,thief); if (rval && (killer == Players[Player_num].objnum)) add_points_to_score(Robot_info[Objects[botnum].id].score_value); } extern fix EnergyToCreateOneRobot; // From fuelcen.c extern object *create_morph_robot(segment *segp, vms_vector *object_pos, int object_id); // from fuelcen.c void multi_do_create_robot(const ubyte *buf) { int fuelcen_num = buf[2]; int pnum = buf[1]; short objnum; int type = buf[5]; FuelCenter *robotcen; vms_vector cur_object_loc, direction; object *obj; objnum = GET_INTEL_SHORT(buf + 3); if ((pnum < 0) || (objnum < 0) || (fuelcen_num < 0) || (fuelcen_num >= Num_fuelcenters) || (pnum >= N_players)) { Int3(); // Bogus data return; } robotcen = &Station[fuelcen_num]; // Play effect and sound compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]); obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT); if (obj) extract_orient_from_segment(&obj->orient, &Segments[robotcen->segnum]); if (Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1) digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 ); // Set robot center flags, in case we become the master for the next one robotcen->Flag = 0; robotcen->Capacity -= EnergyToCreateOneRobot; robotcen->Timer = 0; obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type); if (obj == NULL) return; // Cannot create object! obj->matcen_creator = (robotcen-Station) | 0x80; // extract_orient_from_segment(&obj->orient, &Segments[robotcen->segnum]); vm_vec_sub( &direction, &ConsoleObject->pos, &obj->pos ); vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL); morph_start( obj ); map_objnum_local_to_remote(obj-Objects, objnum, pnum); Assert(obj->ctype.ai_info.REMOTE_OWNER == -1); } void multi_do_boss_actions(const ubyte *buf) { // Code to handle remote-controlled boss actions object *boss_obj; int boss_objnum; int pnum; int action, secondary; int loc = 1; short remote_objnum, segnum; pnum = buf[loc]; loc += 1; boss_objnum = GET_INTEL_SHORT(buf + loc); loc += 2; action = buf[loc]; loc += 1; secondary = buf[loc]; loc += 1; remote_objnum = GET_INTEL_SHORT(buf + loc); loc += 2; segnum = GET_INTEL_SHORT(buf + loc); loc += 2; if ((boss_objnum < 0) || (boss_objnum > Highest_object_index)) { Int3(); // See Rob return; } boss_obj = &Objects[boss_objnum]; if ((boss_obj->type != OBJ_ROBOT) || !(Robot_info[boss_obj->id].boss_flag)) { Int3(); // Got boss actions for a robot who's not a boss? return; } switch(action) { case 1: // Teleport { int teleport_segnum; vms_vector boss_dir; if ((secondary < 0) || (secondary > Num_boss_teleport_segs)) { Int3(); // Bad segnum for boss teleport, ROB!! return; } teleport_segnum = Boss_teleport_segs[secondary]; if ((teleport_segnum < 0) || (teleport_segnum > Highest_segment_index)) { Int3(); // See Rob return; } compute_segment_center(&boss_obj->pos, &Segments[teleport_segnum]); obj_relink(boss_obj-Objects, teleport_segnum); Last_teleport_time = GameTime64; vm_vec_sub(&boss_dir, &Objects[Players[pnum].objnum].pos, &boss_obj->pos); vm_vector_2_matrix(&boss_obj->orient, &boss_dir, NULL, NULL); digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, teleport_segnum, 0, &boss_obj->pos, 0 , F1_0); digi_kill_sound_linked_to_object( boss_obj-Objects); digi_link_sound_to_object2( SOUND_BOSS_SHARE_SEE, boss_obj-Objects, 1, F1_0, F1_0*512 ); // F1_0*512 means play twice as loud Ai_local_info[boss_obj-Objects].next_fire = 0; if (boss_obj->ctype.ai_info.REMOTE_OWNER == Player_num) { multi_delete_controlled_robot(boss_objnum); // robot_controlled[boss_obj->ctype.ai_info.REMOTE_SLOT_NUM] = -1; } boss_obj->ctype.ai_info.REMOTE_OWNER = -1; // Boss is up for grabs again! boss_obj->ctype.ai_info.REMOTE_SLOT_NUM = 0; // Available immediately! } break; case 2: // Cloak Boss_hit_this_frame = 0; Boss_cloak_start_time = GameTime64; Boss_cloak_end_time = GameTime64 + Boss_cloak_duration; boss_obj->ctype.ai_info.CLOAKED = 1; break; case 3: // Gate in robots! { // Do some validity checking if ( (remote_objnum >= MAX_OBJECTS) || (remote_objnum < 0) || (segnum < 0) || (segnum > Highest_segment_index) ) { Int3(); // See Rob, bad data in boss gate action message return; } // Gate one in! if (gate_in_robot(secondary, segnum)) map_objnum_local_to_remote(Net_create_objnums[0], remote_objnum, pnum); } break; case 4: // Start effect restart_effect(ECLIP_NUM_BOSS); break; case 5: // Stop effect stop_effect(ECLIP_NUM_BOSS); break; default: Int3(); // Illegal type to boss actions } } void multi_do_create_robot_powerups(const ubyte *buf) { // Code to drop remote-controlled robot powerups int loc = 1; object del_obj; int pnum, egg_objnum, i; memset( &del_obj, 0, sizeof(object) ); del_obj.type = OBJ_ROBOT; pnum = buf[loc]; loc += 1; del_obj.contains_count = buf[loc]; loc += 1; del_obj.contains_type = buf[loc]; loc += 1; del_obj.contains_id = buf[loc]; loc += 1; del_obj.segnum = GET_INTEL_SHORT(buf + loc); loc += 2; memcpy(&del_obj.pos, buf+loc, sizeof(vms_vector)); loc += 12; vm_vec_zero(&del_obj.mtype.phys_info.velocity); del_obj.pos.x = (fix)INTEL_INT((int)del_obj.pos.x); del_obj.pos.y = (fix)INTEL_INT((int)del_obj.pos.y); del_obj.pos.z = (fix)INTEL_INT((int)del_obj.pos.z); Assert((pnum >= 0) && (pnum < N_players)); Net_create_loc = 0; d_srand(1245L); egg_objnum = object_create_egg(&del_obj); if (egg_objnum == -1) return; // Object buffer full // Assert(egg_objnum > -1); Assert((Net_create_loc > 0) && (Net_create_loc <= MAX_ROBOT_POWERUPS)); for (i = 0; i < Net_create_loc; i++) { short s; s = GET_INTEL_SHORT(buf + loc); if ( s != -1) map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum); else Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD; // Delete objects other guy didn't create one of loc += 2; } } void multi_drop_robot_powerups(int objnum) { // Code to handle dropped robot powerups in network mode ONLY! object *del_obj; int egg_objnum = -1; robot_info *robptr; if ((objnum < 0) || (objnum > Highest_object_index)) { Int3(); // See rob return; } del_obj = &Objects[objnum]; if (del_obj->type != OBJ_ROBOT) { Int3(); // dropping powerups for non-robot, Rob's fault return; } robptr = &Robot_info[del_obj->id]; Net_create_loc = 0; if (del_obj->contains_count > 0) { // If dropping a weapon that the player has, drop energy instead, unless it's vulcan, in which case drop vulcan ammo. if (del_obj->contains_type == OBJ_POWERUP) { maybe_replace_powerup_with_energy(del_obj); // No key drops in non-coop games! if (!(Game_mode & GM_MULTI_COOP)) { if ((del_obj->contains_id >= POW_KEY_BLUE) && (del_obj->contains_id <= POW_KEY_GOLD)) del_obj->contains_count = 0; } } d_srand(1245L); if (del_obj->contains_count > 0) egg_objnum = object_create_egg(del_obj); } else if (del_obj->ctype.ai_info.REMOTE_OWNER == -1) // No random goodies for robots we weren't in control of return; else if (robptr->contains_count) { d_srand((fix)timer_query()); if (((d_rand() * 16) >> 15) < robptr->contains_prob) { del_obj->contains_count = ((d_rand() * robptr->contains_count) >> 15) + 1; del_obj->contains_type = robptr->contains_type; del_obj->contains_id = robptr->contains_id; if (del_obj->contains_type == OBJ_POWERUP) maybe_replace_powerup_with_energy(del_obj); d_srand(1245L); if (del_obj->contains_count > 0) egg_objnum = object_create_egg(del_obj); } } if (egg_objnum >= 0) { // Transmit the object creation to the other players multi_send_create_robot_powerups(del_obj); } } // ----------------------------------------------------------------------------- // Robot *robot got whacked by player player_num and requests permission to do something about it. // Note: This function will be called regardless of whether Game_mode is a multiplayer mode, so it // should quick-out if not in a multiplayer mode. On the other hand, it only gets called when a // player or player weapon whacks a robot, so it happens rarely. void multi_robot_request_change(object *robot, int player_num) { int slot, remote_objnum; sbyte dummy; if (!(Game_mode & GM_MULTI_ROBOTS)) return; if (robot->ctype.ai_info.REMOTE_OWNER != Player_num) return; slot = robot->ctype.ai_info.REMOTE_SLOT_NUM; if ((slot < 0) || (slot >= MAX_ROBOTS_CONTROLLED)) { Int3(); return; } remote_objnum = objnum_local_to_remote(robot-Objects, &dummy); if (remote_objnum < 0) return; if ( (robot_agitation[slot] < 70) || (MULTI_ROBOT_PRIORITY(remote_objnum, player_num) > MULTI_ROBOT_PRIORITY(remote_objnum, Player_num)) || (d_rand() > 0x4400)) { if (robot_send_pending[slot]) multi_send_robot_position(robot_controlled[slot], -1); multi_send_release_robot(robot_controlled[slot]); robot->ctype.ai_info.REMOTE_SLOT_NUM = 5; // Hands-off period } } #endif #endif dxx-rebirth-0.58.1-d1x/main/multibot.h000066400000000000000000000043121217717257200175060ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header file for multiplayer robot support. * */ #ifdef NETWORK #ifndef _MULTIBOT_H #define _MULTIBOT_H #ifndef SHAREWARE #define MAX_ROBOTS_CONTROLLED 3 #define ROBOT_FIRE_AGITATION 94 extern int robot_controlled[MAX_ROBOTS_CONTROLLED]; extern int robot_agitation[MAX_ROBOTS_CONTROLLED]; extern int robot_fired[MAX_ROBOTS_CONTROLLED]; int multi_can_move_robot(int objnum, int agitation); void multi_send_robot_position(int objnum, int fired); void multi_send_robot_fire(int objnum, int gun_num, vms_vector *fire); void multi_send_claim_robot(int objnum); void multi_send_robot_explode(int objnum, int killer, char unused); void multi_send_create_robot(int robotcen, int objnum, int type); void multi_send_boss_actions(int bossobjnum, int action, int secondary, int objnum); int multi_send_robot_frame(int sent); void multi_do_robot_explode(const ubyte *buf); void multi_do_robot_position(const ubyte *buf); void multi_do_claim_robot(const ubyte *buf); void multi_do_release_robot(const ubyte *buf); void multi_do_robot_fire(const ubyte *buf); void multi_do_create_robot(const ubyte *buf); void multi_do_boss_actions(const ubyte *buf); void multi_do_create_robot_powerups(const ubyte *buf); int multi_explode_robot_sub(int botnum, int killer, char unused); void multi_drop_robot_powerups(int objnum); void multi_dump_robots(void); void multi_strip_robots(int playernum); void multi_check_robot_timeout(void); void multi_robot_request_change(object *robot, int playernum); #endif #endif #endif dxx-rebirth-0.58.1-d1x/main/net_udp.c000066400000000000000000004433121217717257200173070ustar00rootroot00000000000000/* * * Routines for managing UDP-protocol network play. * */ #ifdef NETWORK #include #include #include #include "pstypes.h" #include "window.h" #include "strutil.h" #include "args.h" #include "timer.h" #include "newmenu.h" #include "key.h" #include "gauges.h" #include "object.h" #include "dxxerror.h" #include "laser.h" #include "gamesave.h" #include "gamemine.h" #include "player.h" #include "gameseq.h" #include "fireball.h" #include "net_udp.h" #include "game.h" #include "multi.h" #include "endlevel.h" #include "palette.h" #include "cntrlcen.h" #include "menu.h" #include "sounds.h" #include "text.h" #include "kmatrix.h" #include "newdemo.h" #include "multibot.h" #include "wall.h" #include "bm.h" #include "effects.h" #include "physics.h" #include "vers_id.h" #include "gamefont.h" #include "playsave.h" #include "rbaudio.h" #include "byteswap.h" #include "config.h" #include "vers_id.h" // Prototypes void net_udp_init(); void net_udp_close(); void net_udp_request_game_info(struct _sockaddr game_addr, int lite); void net_udp_listen(); int net_udp_show_game_info(); int net_udp_do_join_game(); int net_udp_can_join_netgame(netgame_info *game); void net_udp_flush(); void net_udp_update_netgame(void); void net_udp_send_objects(void); void net_udp_send_rejoin_sync(int player_num); void net_udp_send_game_info(struct _sockaddr sender_addr, ubyte info_upid); void net_udp_send_netgame_update(); void net_udp_do_refuse_stuff (UDP_sequence_packet *their); void net_udp_read_sync_packet( ubyte * data, int data_len, struct _sockaddr sender_addr ); void net_udp_read_object_packet( ubyte *data ); void net_udp_ping_frame(fix64 time); void net_udp_process_ping(ubyte *data, int data_len, struct _sockaddr sender_addr); void net_udp_process_pong(ubyte *data, int data_len, struct _sockaddr sender_addr); void net_udp_process_game_info(ubyte *data, int data_len, struct _sockaddr game_addr, int lite_info); void net_udp_read_endlevel_packet( ubyte *data, int data_len, struct _sockaddr sender_addr ); void net_udp_send_mdata(int needack, fix64 time); void net_udp_process_mdata (ubyte *data, int data_len, struct _sockaddr sender_addr, int needack); void net_udp_send_pdata(); void net_udp_process_pdata ( ubyte *data, int data_len, struct _sockaddr sender_addr ); void net_udp_read_pdata_packet(UDP_frame_info *pd); void net_udp_timeout_check(fix64 time); int net_udp_get_new_player_num (UDP_sequence_packet *their); void net_udp_noloss_add_queue_pkt(uint32_t pkt_num, fix64 time, ubyte *data, ushort data_size, ubyte pnum, ubyte player_ack[MAX_PLAYERS]); int net_udp_noloss_validate_mdata(uint32_t pkt_num, ubyte sender_pnum, struct _sockaddr sender_addr); void net_udp_noloss_got_ack(ubyte *data, int data_len); void net_udp_noloss_init_mdata_queue(void); void net_udp_noloss_clear_mdata_got(ubyte player_num); void net_udp_noloss_process_queue(fix64 time); void net_udp_send_extras (); static void net_udp_broadcast_game_info(ubyte info_upid); // Variables int UDP_num_sendto = 0, UDP_len_sendto = 0, UDP_num_recvfrom = 0, UDP_len_recvfrom = 0; UDP_mdata_info UDP_MData; UDP_sequence_packet UDP_Seq; UDP_mdata_store UDP_mdata_queue[UDP_MDATA_STOR_QUEUE_SIZE]; UDP_mdata_recv UDP_mdata_got[MAX_PLAYERS]; UDP_sequence_packet UDP_sync_player; // For rejoin object syncing UDP_netgame_info_lite Active_udp_games[UDP_MAX_NETGAMES]; int num_active_udp_games = 0; int num_active_udp_changed = 0; static int UDP_Socket[3] = { -1, -1, -1 }; static char UDP_MyPort[6] = ""; struct _sockaddr GBcast; // global Broadcast address clients and hosts will use for lite_info exchange over LAN #ifdef IPv6 struct _sockaddr GMcast_v6; // same for IPv6-only #endif #ifdef USE_TRACKER struct _sockaddr TrackerSocket; int iTrackerVerified = 0; #endif extern obj_position Player_init[MAX_PLAYERS]; /* General UDP functions - START */ ssize_t dxx_sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen) { ssize_t rv = sendto(sockfd, msg, len, flags, to, tolen); UDP_num_sendto++; if (rv > 0) UDP_len_sendto += rv; return rv; } ssize_t dxx_recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen) { ssize_t rv = recvfrom(sockfd, buf, len, flags, from, fromlen); UDP_num_recvfrom++; UDP_len_recvfrom += rv; return rv; } void udp_traffic_stat() { static fix64 last_traf_time = 0; if (timer_query() >= last_traf_time + F1_0) { last_traf_time = timer_query(); con_printf(CON_VERBOSE, "P#%i TRAFFIC - OUT: %fKB/s %iPPS IN: %fKB/s %iPPS\n",Player_num, (float)UDP_len_sendto/1024, UDP_num_sendto, (float)UDP_len_recvfrom/1024, UDP_num_recvfrom); UDP_num_sendto = UDP_len_sendto = UDP_num_recvfrom = UDP_len_recvfrom = 0; } } // Resolve address int udp_dns_filladdr( char *host, int port, struct _sockaddr *sAddr ) { // Variables struct addrinfo *result, hints; char sPort[6]; // Build the port snprintf( sPort, 6, "%d", port ); // Set up hints memset( &hints, 0, sizeof( hints ) ); // Uncomment the following if we want ONLY what we compile for // hints.ai_family = _af; // We are always UDP hints.ai_socktype = SOCK_DGRAM; // Resolve the domain name if( getaddrinfo( host, sPort, &hints, &result ) != 0 ) { con_printf( CON_URGENT, "udp_dns_filladdr (getaddrinfo) failed\n" ); nm_messagebox( TXT_ERROR, 1, TXT_OK, "Could not resolve address" ); return -1; } // Zero out the target first memset( sAddr, 0, sizeof( struct _sockaddr ) ); // Now copy it over memcpy( sAddr, result->ai_addr, result->ai_addrlen ); /* WARNING: NERDY CONTENT * * The above works, since result->ai_addr contains the socket family, * which is copied into our struct. Our struct will be read for sendto * and recvfrom, using the sockaddr.sa_family member. If we are IPv6, * this already has enough space to read into. If we are IPv4, we will * not be able to get any IPv6 connections anyway, so we will be safe * from an overflow. The more you know, 'cause knowledge is power! * * -- Matt */ // Free memory freeaddrinfo( result ); return 0; } // Closes an existing udp socket void udp_close_socket(int socknum) { if (UDP_Socket[socknum] != -1) { #ifdef _WIN32 closesocket(UDP_Socket[socknum]); #else close (UDP_Socket[socknum]); #endif } UDP_Socket[socknum] = -1; } // Open socket int udp_open_socket(int socknum, int port) { int bcast = 1; // close stale socket if( UDP_Socket[socknum] != -1 ) udp_close_socket(socknum); { #ifdef _WIN32 struct _sockaddr sAddr; // my address information memset( &sAddr, '\0', sizeof( sAddr ) ); if ((UDP_Socket[socknum] = socket (_af, SOCK_DGRAM, 0)) < 0) { con_printf(CON_URGENT,"udp_open_socket: socket creation failed (port %i)\n", port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nCould not create socket.", port); return -1; } #ifdef IPv6 sAddr.sin6_family = _pf; // host byte order sAddr.sin6_port = htons (port); // short, network byte order sAddr.sin6_flowinfo = 0; sAddr.sin6_addr = in6addr_any; // automatically fill with my IP sAddr.sin6_scope_id = 0; #else sAddr.sin_family = _pf; // host byte order sAddr.sin_port = htons (port); // short, network byte order sAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset (&(sAddr.sin_zero), '\0', 8); // zero the rest of the struct #endif if (bind (UDP_Socket[socknum], (struct sockaddr *) &sAddr, sizeof (struct sockaddr)) < 0) { con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed (port %i)\n", port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nCould not bind name to socket.", port); udp_close_socket(socknum); return -1; } (void)setsockopt( UDP_Socket[socknum], SOL_SOCKET, SO_BROADCAST, (const char *) &bcast, sizeof(bcast) ); #else struct addrinfo hints,*res,*sres; int err,ai_family_; char cport[6]; memset (&hints, '\0', sizeof (struct addrinfo)); memset(cport,'\0',sizeof(char)*6); hints.ai_flags = AI_PASSIVE; hints.ai_family = _pf; hints.ai_socktype = SOCK_DGRAM; ai_family_ = 0; sprintf(cport,"%i",port); if ((err = getaddrinfo (NULL, cport, &hints, &res)) == 0) { sres = res; while ((ai_family_ == 0) && (sres)) { if (sres->ai_family == _pf || _pf == PF_UNSPEC) ai_family_ = sres->ai_family; else sres = sres->ai_next; } if (sres == NULL) sres = res; ai_family_ = sres->ai_family; if (ai_family_ != _pf && _pf != PF_UNSPEC) { // ai_family is not identic freeaddrinfo (res); con_printf(CON_URGENT,"udp_open_socket: ai_family not identic (port %i)\n", port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nai_family_not identic.", port); return -1; } if ((UDP_Socket[socknum] = socket (sres->ai_family, SOCK_DGRAM, 0)) < 0) { con_printf(CON_URGENT,"udp_open_socket: socket creation failed (port %i)\n", port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nCould not create socket.", port); freeaddrinfo (res); return -1; } if ((err = bind (UDP_Socket[socknum], sres->ai_addr, sres->ai_addrlen)) < 0) { con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed (port %i)\n", port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nCould not bind name to socket.", port); udp_close_socket(socknum); freeaddrinfo (res); return -1; } freeaddrinfo (res); } else { UDP_Socket[socknum] = -1; con_printf(CON_URGENT,"udp_open_socket (getaddrinfo):%s failed. port %i\n", gai_strerror (err), port); nm_messagebox(TXT_ERROR,1,TXT_OK,"Port: %i\nCould not get address information:\n%s", port, gai_strerror (err)); } setsockopt( UDP_Socket[socknum], SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast) ); #endif return 0; } } int udp_general_packet_ready(int socknum) { fd_set set; struct timeval tv; FD_ZERO(&set); FD_SET(UDP_Socket[socknum], &set); tv.tv_sec = tv.tv_usec = 0; if (select(UDP_Socket[socknum] + 1, &set, NULL, NULL, &tv) > 0) return 1; else return 0; } // Gets some text. Returns 0 if nothing on there. int udp_receive_packet(int socknum, ubyte *text, int len, struct _sockaddr *sender_addr) { socklen_t clen = sizeof (struct _sockaddr); ssize_t msglen = 0; if (UDP_Socket[socknum] == -1) return -1; if (udp_general_packet_ready(socknum)) { msglen = dxx_recvfrom (UDP_Socket[socknum], text, len, 0, (struct sockaddr *)sender_addr, &clen); if (msglen < 0) return 0; if ((msglen >= 0) && (msglen < len)) text[msglen] = 0; } return msglen; } /* General UDP functions - END */ /* Tracker stuff, begin! */ #ifdef USE_TRACKER /* Tracker defines: System stuff */ #define TRACKER_SYS_VERSION 0x00 /* Tracker protocol version */ /* Tracker defines: Packet stuff */ #define TRACKER_PKT_REGISTER 0 /* Register a game */ #define TRACKER_PKT_UNREGISTER 1 /* Unregister our game */ #define TRACKER_PKT_GAMELIST 2 /* Request the game list */ /* Tracker initialization */ int udp_tracker_init() { int tracker_port = d_rand() % 0xffff; while (tracker_port <= 1024) tracker_port = d_rand() % 0xffff; // Zero it out memset( &TrackerSocket, 0, sizeof( TrackerSocket ) ); // Open the socket udp_open_socket( 2, tracker_port ); // Fill the address if( udp_dns_filladdr( (char *)GameArg.MplTrackerAddr, GameArg.MplTrackerPort, &TrackerSocket ) < 0 ) return -1; // Yay return 0; } /* Unregister from the tracker */ int udp_tracker_unregister() { // Variables int iLen = 5; ubyte pBuf[iLen]; // Put the opcode pBuf[0] = TRACKER_PKT_UNREGISTER; // Put the GameID PUT_INTEL_INT( pBuf+1, Netgame.protocol.udp.GameID ); // Send it off return dxx_sendto( UDP_Socket[2], pBuf, iLen, 0, (struct sockaddr *)&TrackerSocket, sizeof( TrackerSocket ) ); } /* Tell the tracker we're starting a game */ int udp_tracker_register() { // Variables int iLen = 14; ubyte pBuf[iLen]; // Reset the last tracker message iTrackerVerified = 0; // Put the opcode pBuf[0] = TRACKER_PKT_REGISTER; // Put the protocol version pBuf[1] = TRACKER_SYS_VERSION; // Write the game version (d1 = 1, d2 = 2, x = oshiii) pBuf[2] = 0x01; // Write the port we're running on PUT_INTEL_SHORT( pBuf+3, atoi( UDP_MyPort ) ); // Put the GameID PUT_INTEL_INT( pBuf+5, Netgame.protocol.udp.GameID ); // Now, put the game version PUT_INTEL_SHORT( pBuf+9, DXX_VERSION_MAJORi ); PUT_INTEL_SHORT( pBuf+11, DXX_VERSION_MINORi ); PUT_INTEL_SHORT( pBuf+13, DXX_VERSION_MICROi ); // Send it off return dxx_sendto( UDP_Socket[2], pBuf, iLen, 0, (struct sockaddr *)&TrackerSocket, sizeof( TrackerSocket ) ); } /* Ask the tracker to send us a list of games */ int udp_tracker_reqgames() { // Variables int iLen = 3; ubyte pBuf[iLen]; // Put the opcode pBuf[0] = TRACKER_PKT_GAMELIST; // // Put the game version (d1) pBuf[1] = 1; // If we're IPv6 ready, send that too #ifdef IPv6 pBuf[2] = 1; #else pBuf[2] = 0; #endif // Send it off return dxx_sendto( UDP_Socket[2], pBuf, iLen, 0, (struct sockaddr *)&TrackerSocket, sizeof( TrackerSocket ) ); } /* The tracker has sent us a game. Let's list it. */ int udp_tracker_process_game( ubyte *data, int data_len ) { // All our variables struct _sockaddr sAddr; int iPos = 1; int iPort = 0; int bIPv6 = 0; char *sIP = NULL; // Zero it out memset( &sAddr, 0, sizeof( sAddr ) ); // Get the IPv6 flag from the tracker bIPv6 = data[iPos++]; (void)bIPv6; // currently unused // Get the IP sIP = (char *)&data[iPos]; iPos += strlen( sIP ) + 1; // Get the port iPort = GET_INTEL_SHORT( &data[iPos] ); iPos += 2; // Get the DNS stuff if( udp_dns_filladdr( sIP, iPort, &sAddr ) < 0 ) return -1; // Now move on to BIGGER AND BETTER THINGS! net_udp_process_game_info( &data[iPos - 1], data_len - iPos, sAddr, 1 ); return 0; } #endif /* USE_TRACKER */ typedef struct direct_join { struct _sockaddr host_addr; int connecting; fix64 start_time, last_time; char addrbuf[128]; char portbuf[6]; } direct_join; // Connect to a game host and get full info. Eventually we join! int net_udp_game_connect(direct_join *dj) { // Get full game info so we can show it. // Timeout after 10 seconds if (timer_query() >= dj->start_time + (F1_0*10)) { nm_messagebox(TXT_ERROR,1,TXT_OK,"No response by host.\n\nPossible reasons:\n* No game on this IP (anymore)\n* Port of Host not open\n or different\n* Host uses a game version\n I do not understand"); dj->connecting = 0; return 0; } if (Netgame.protocol.udp.valid == -1) { nm_messagebox(TXT_ERROR,1,TXT_OK,"Version mismatch! Cannot join Game.\nHost game version: %i.%i.%i\nHost game protocol: %i\nYour game version: %s\nYour game protocol: %i",Netgame.protocol.udp.program_iver[0],Netgame.protocol.udp.program_iver[1],Netgame.protocol.udp.program_iver[2],Netgame.protocol.udp.program_iver[3],VERSION, MULTI_PROTO_VERSION); dj->connecting = 0; return 0; } if (timer_query() >= dj->last_time + F1_0) { net_udp_request_game_info(dj->host_addr, 0); dj->last_time = timer_query(); } timer_delay2(5); net_udp_listen(); if (Netgame.protocol.udp.valid != 1) return 0; // still trying to connect if (dj->connecting == 1) { if (!net_udp_show_game_info()) // show info menu and check if we join { dj->connecting = 0; return 0; } else { // Get full game info again as it could have changed since we entered the info menu. dj->connecting = 2; Netgame.protocol.udp.valid = 0; dj->start_time = timer_query(); return 0; } } dj->connecting = 0; return net_udp_do_join_game(); } static char *connecting_txt = "Connecting..."; static char *blank = ""; static int manual_join_game_handler(newmenu *menu, d_event *event, direct_join *dj) { newmenu_item *items = newmenu_get_items(menu); switch (event->type) { case EVENT_KEY_COMMAND: if (dj->connecting && event_key_get(event) == KEY_ESC) { dj->connecting = 0; items[6].text = blank; return 1; } break; case EVENT_IDLE: if (dj->connecting) { if (net_udp_game_connect(dj)) return -2; // Success! else if (!dj->connecting) items[6].text = blank; } break; case EVENT_NEWMENU_SELECTED: { int sockres = -1; net_udp_init(); // yes, redundant call but since the menu does not know any better it would allow any IP entry as long as Netgame-entry looks okay... my head hurts... if ((atoi(UDP_MyPort)) <= 1024 ||(atoi(UDP_MyPort)) > 65535) { snprintf (UDP_MyPort, sizeof(UDP_MyPort), "%d", UDP_PORT_DEFAULT); nm_messagebox(TXT_ERROR, 1, TXT_OK, "Illegal port"); return 1; } sockres = udp_open_socket(0, atoi(UDP_MyPort)); if (sockres != 0) { return 1; } // Resolve address if (udp_dns_filladdr(dj->addrbuf, atoi(dj->portbuf), &dj->host_addr) < 0) { return 1; } else { multi_new_game(); N_players = 0; change_playernum_to(1); dj->start_time = timer_query(); dj->last_time = 0; memcpy((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&dj->host_addr, sizeof(struct _sockaddr)); dj->connecting = 1; items[6].text = connecting_txt; return 1; } break; } case EVENT_WINDOW_CLOSE: if (!Game_wind) // they cancelled net_udp_close(); d_free(dj); break; default: break; } return 0; } void net_udp_manual_join_game() { direct_join *dj; newmenu_item m[7]; int nitems = 0; MALLOC(dj, direct_join, 1); if (!dj) return; dj->connecting = 0; dj->addrbuf[0] = '\0'; dj->portbuf[0] = '\0'; net_udp_init(); memset(&dj->addrbuf,'\0', sizeof(char)*128); snprintf(dj->addrbuf, sizeof(dj->addrbuf), "%s", GameArg.MplUdpHostAddr); if (GameArg.MplUdpHostPort != 0) snprintf(dj->portbuf, sizeof(dj->portbuf), "%d", GameArg.MplUdpHostPort); else snprintf(dj->portbuf, sizeof(dj->portbuf), "%d", UDP_PORT_DEFAULT); if (GameArg.MplUdpMyPort != 0) snprintf (UDP_MyPort, sizeof(UDP_MyPort), "%d", GameArg.MplUdpMyPort); else snprintf (UDP_MyPort, sizeof(UDP_MyPort), "%d", UDP_PORT_DEFAULT); nitems = 0; m[nitems].type = NM_TYPE_TEXT; m[nitems].text="GAME ADDRESS OR HOSTNAME:"; nitems++; m[nitems].type = NM_TYPE_INPUT; m[nitems].text=dj->addrbuf; m[nitems].text_len=128; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text="GAME PORT:"; nitems++; m[nitems].type = NM_TYPE_INPUT; m[nitems].text=dj->portbuf; m[nitems].text_len=5; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text="MY PORT:"; nitems++; m[nitems].type = NM_TYPE_INPUT; m[nitems].text=UDP_MyPort; m[nitems].text_len=5; nitems++; m[nitems].type = NM_TYPE_TEXT; m[nitems].text=blank; nitems++; // for connecting_txt newmenu_do1( NULL, "ENTER GAME ADDRESS", nitems, m, (int (*)(newmenu *, d_event *, void *))manual_join_game_handler, dj, 0 ); } static char *ljtext; int net_udp_list_join_poll( newmenu *menu, d_event *event, direct_join *dj ) { // Polling loop for Join Game menu int i, newpage = 0; static int NLPage = 0; newmenu_item *menus = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); switch (event->type) { case EVENT_WINDOW_ACTIVATED: { Netgame.protocol.udp.valid = 0; memset(Active_udp_games, 0, sizeof(UDP_netgame_info_lite)*UDP_MAX_NETGAMES); num_active_udp_changed = 1; num_active_udp_games = 0; net_udp_request_game_info(GBcast, 1); #ifdef IPv6 net_udp_request_game_info(GMcast_v6, 1); #endif #ifdef USE_TRACKER udp_tracker_reqgames(); #endif break; } case EVENT_IDLE: if (dj->connecting) { if (net_udp_game_connect(dj)) return -2; // Success! } break; case EVENT_KEY_COMMAND: { int key = event_key_get(event); if (key == KEY_PAGEUP) { NLPage--; newpage++; if (NLPage < 0) NLPage = UDP_NETGAMES_PAGES-1; key = 0; break; } if (key == KEY_PAGEDOWN) { NLPage++; newpage++; if (NLPage >= UDP_NETGAMES_PAGES) NLPage = 0; key = 0; break; } if( key == KEY_F4 ) { // Empty the list memset(Active_udp_games, 0, sizeof(UDP_netgame_info_lite)*UDP_MAX_NETGAMES); num_active_udp_changed = 1; num_active_udp_games = 0; // Request LAN games net_udp_request_game_info(GBcast, 1); #ifdef IPv6 net_udp_request_game_info(GMcast_v6, 1); #endif #ifdef USE_TRACKER udp_tracker_reqgames(); #endif // All done break; } if (key == KEY_F5) { memset(Active_udp_games, 0, sizeof(UDP_netgame_info_lite)*UDP_MAX_NETGAMES); num_active_udp_changed = 1; num_active_udp_games = 0; net_udp_request_game_info(GBcast, 1); #ifdef IPv6 net_udp_request_game_info(GMcast_v6, 1); #endif break; } #ifdef USE_TRACKER if( key == KEY_F6 ) { // Zero the list memset( Active_udp_games, 0, sizeof( UDP_netgame_info_lite ) * UDP_MAX_NETGAMES ); num_active_udp_changed = 1; num_active_udp_games = 0; // Request from the tracker udp_tracker_reqgames(); // Break off break; } #endif if (key == KEY_ESC) { if (dj->connecting) { dj->connecting = 0; return 1; } break; } break; } case EVENT_NEWMENU_SELECTED: { if (((citem+(NLPage*UDP_NETGAMES_PPAGE)) >= 4) && (((citem+(NLPage*UDP_NETGAMES_PPAGE))-4) <= num_active_udp_games-1)) { multi_new_game(); N_players = 0; change_playernum_to(1); dj->start_time = timer_query(); dj->last_time = 0; memcpy((struct _sockaddr *)&dj->host_addr, (struct _sockaddr *)&Active_udp_games[(citem+(NLPage*UDP_NETGAMES_PPAGE))-4].game_addr, sizeof(struct _sockaddr)); memcpy((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&dj->host_addr, sizeof(struct _sockaddr)); dj->connecting = 1; return 1; } else { nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_INVALID_CHOICE); return -1; // invalid game selected - stay in the menu } break; } case EVENT_WINDOW_CLOSE: { d_free(ljtext); d_free(menus); d_free(dj); if (!Game_wind) { net_udp_close(); Network_status = NETSTAT_MENU; // they cancelled } return 0; } default: break; } net_udp_listen(); if (!num_active_udp_changed && !newpage) return 0; num_active_udp_changed = 0; // Copy the active games data into the menu options for (i = 0; i < UDP_NETGAMES_PPAGE; i++) { int game_status = Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].game_status; int j,x, k,tx,ty,ta,nplayers = 0; char levelname[8],MissName[25],GameName[25],thold[2],status[8]; thold[1]=0; if ((i+(NLPage*UDP_NETGAMES_PPAGE)) >= num_active_udp_games) { snprintf(menus[i+4].text, sizeof(char)*74, "%d. ",(i+(NLPage*UDP_NETGAMES_PPAGE))+1); continue; } // These next two loops protect against menu skewing // if missiontitle or gamename contain a tab for (x=0,tx=0,k=0,j=0;j<15;j++) { if (Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].mission_title[j]=='\t') continue; thold[0]=Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].mission_title[j]; gr_get_string_size (thold,&tx,&ty,&ta); if ((x+=tx)>=FSPACX(55)) { MissName[k]=MissName[k+1]=MissName[k+2]='.'; k+=3; break; } MissName[k++]=Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].mission_title[j]; } MissName[k]=0; for (x=0,tx=0,k=0,j=0;j<15;j++) { if (Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].game_name[j]=='\t') continue; thold[0]=Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].game_name[j]; gr_get_string_size (thold,&tx,&ty,&ta); if ((x+=tx)>=FSPACX(55)) { GameName[k]=GameName[k+1]=GameName[k+2]='.'; k+=3; break; } GameName[k++]=Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].game_name[j]; } GameName[k]=0; nplayers = Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].numconnected; if (Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].levelnum < 0) snprintf(levelname, sizeof(levelname), "S%d", -Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].levelnum); else snprintf(levelname, sizeof(levelname), "%d", Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].levelnum); if (game_status == NETSTAT_STARTING) snprintf(status, sizeof(status), "FORMING "); else if (game_status == NETSTAT_PLAYING) { if (Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].RefusePlayers) snprintf(status, sizeof(status), "RESTRICT"); else if (Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].game_flags & NETGAME_FLAG_CLOSED) snprintf(status, sizeof(status), "CLOSED "); else snprintf(status, sizeof(status), "OPEN "); } else snprintf(status, sizeof(status), "BETWEEN "); unsigned gamemode = Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].gamemode; snprintf (menus[i+4].text,sizeof(char)*74,"%d.\t%s \t%s \t %d/%d \t%s \t %s \t%s",(i+(NLPage*UDP_NETGAMES_PPAGE))+1,GameName,(gamemode < sizeof(GMNamesShrt) / sizeof(GMNamesShrt[0])) ? GMNamesShrt[gamemode] : "INVALID",nplayers, Active_udp_games[(i+(NLPage*UDP_NETGAMES_PPAGE))].max_numplayers,MissName,levelname,status); Assert(strlen(menus[i+4].text) < 75); } return 0; } void net_udp_list_join_game() { int i = 0; newmenu_item *m; direct_join *dj; MALLOC(m, newmenu_item, ((UDP_NETGAMES_PPAGE+4)*2)+1); if (!m) return; MALLOC(ljtext, char, (((UDP_NETGAMES_PPAGE+4)*2)+1)*74); if (!ljtext) { d_free(m); return; } MALLOC(dj, direct_join, 1); if (!dj) return; dj->connecting = 0; dj->addrbuf[0] = '\0'; dj->portbuf[0] = '\0'; net_udp_init(); if (udp_open_socket(0, GameArg.MplUdpMyPort != 0?GameArg.MplUdpMyPort:UDP_PORT_DEFAULT) < 0) return; if (GameArg.MplUdpMyPort != 0) if (udp_open_socket(1, UDP_PORT_DEFAULT) < 0) nm_messagebox(TXT_WARNING, 1, TXT_OK, "Cannot open default port!\nYou can only scan for games\nmanually."); // prepare broadcast address to discover games memset(&GBcast, '\0', sizeof(struct _sockaddr)); udp_dns_filladdr(UDP_BCAST_ADDR, UDP_PORT_DEFAULT, &GBcast); #ifdef IPv6 memset(&GMcast_v6, '\0', sizeof(struct _sockaddr)); udp_dns_filladdr(UDP_MCASTv6_ADDR, UDP_PORT_DEFAULT, &GMcast_v6); #endif change_playernum_to(1); N_players = 0; Network_send_objects = 0; Network_sending_extras=0; Network_rejoined=0; Network_status = NETSTAT_BROWSING; // We are looking at a game menu net_udp_flush(); net_udp_listen(); // Throw out old info num_active_udp_games = 0; memset(m, 0, sizeof(newmenu_item)*(UDP_NETGAMES_PPAGE+2)); memset(Active_udp_games, 0, sizeof(UDP_netgame_info_lite)*UDP_MAX_NETGAMES); gr_set_fontcolor(BM_XRGB(15,15,23),-1); m[0].text = ljtext; m[0].type = NM_TYPE_TEXT; snprintf( m[0].text, sizeof(char)*74, "\tF4/F5/F6: (Re)Scan for all/LAN/Tracker Games." ); m[1].text = ljtext + 74*1; m[1].type = NM_TYPE_TEXT; snprintf( m[1].text, sizeof(char)*74, "\tPgUp/PgDn: Flip Pages." ); m[2].text = ljtext + 74*2; m[2].type = NM_TYPE_TEXT; snprintf( m[2].text, sizeof(char)*74, " " ); m[3].text = ljtext + 74*3; m[3].type = NM_TYPE_TEXT; snprintf (m[3].text, sizeof(char)*74, "\tGAME \tMODE \t#PLYRS \tMISSION \tLEV \tSTATUS"); for (i = 0; i < UDP_NETGAMES_PPAGE; i++) { m[i+4].text = ljtext + 74 * (i+4); m[i+4].type = NM_TYPE_MENU; snprintf(m[i+4].text,sizeof(char)*74,"%d. ", i+1); } num_active_udp_changed = 1; newmenu_dotiny("NETGAMES", NULL,(UDP_NETGAMES_PPAGE+4), m, 1, (int (*)(newmenu *, d_event *, void *))net_udp_list_join_poll, dj); } void net_udp_send_sequence_packet(UDP_sequence_packet seq, struct _sockaddr recv_addr) { int len = 0; ubyte buf[UPID_SEQUENCE_SIZE]; len = 0; memset(buf, 0, sizeof(buf)); buf[0] = seq.type; len++; memcpy(&buf[len], seq.player.callsign, CALLSIGN_LEN+1); len += CALLSIGN_LEN+1; buf[len] = seq.player.connected; len++; buf[len] = seq.player.rank; len++; dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&recv_addr, sizeof(struct _sockaddr)); } void net_udp_receive_sequence_packet(ubyte *data, UDP_sequence_packet *seq, struct _sockaddr sender_addr) { int len = 0; seq->type = data[0]; len++; memcpy(seq->player.callsign, &(data[len]), CALLSIGN_LEN+1); len += CALLSIGN_LEN+1; seq->player.connected = data[len]; len++; memcpy (&(seq->player.rank),&(data[len]),1); len++; if (multi_i_am_master()) memcpy(&seq->player.protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr)); } void net_udp_init() { // So you want to play a netgame, eh? Let's a get a few things straight #ifdef _WIN32 { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSACleanup(); if (WSAStartup( wVersionRequested, &wsaData)) nm_messagebox( TXT_ERROR, 1, TXT_OK, "Cannot init Winsock!"); // no break here... game will fail at socket creation anyways... } #endif if( UDP_Socket[0] != -1 ) udp_close_socket(0); if( UDP_Socket[1] != -1 ) udp_close_socket(1); memset(&Netgame, 0, sizeof(netgame_info)); memset(&UDP_Seq, 0, sizeof(UDP_sequence_packet)); memset(&UDP_MData, 0, sizeof(UDP_mdata_info)); net_udp_noloss_init_mdata_queue(); UDP_Seq.type = UPID_REQUEST; memcpy(UDP_Seq.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1); UDP_Seq.player.rank=GetMyNetRanking(); multi_new_game(); net_udp_flush(); #ifdef USE_TRACKER // Initialize the tracker info udp_tracker_init(); #endif } void net_udp_close() { #ifdef _WIN32 WSACleanup(); #endif if( UDP_Socket[0] != -1 ) udp_close_socket(0); if( UDP_Socket[1] != -1 ) udp_close_socket(1); if( UDP_Socket[2] != -1 ) udp_close_socket(2); } // Send PID_ENDLEVEL in regular intervals and listen for them (host also does the packets for playing clients) int net_udp_kmatrix_poll1( newmenu *menu, d_event *event, void *userdata ) { // Polling loop for End-of-level menu if (event->type != EVENT_WINDOW_DRAW) return 0; menu = menu; userdata = userdata; net_udp_do_frame(0, 1); return 0; } // Same as above but used when player pressed ESC during kmatrix (host also does the packets for playing clients) extern fix64 StartAbortMenuTime; int net_udp_kmatrix_poll2( newmenu *menu, d_event *event, void *userdata ) { int rval = 0; // Polling loop for End-of-level menu if (event->type != EVENT_WINDOW_DRAW) return 0; menu = menu; userdata = userdata; if (timer_query() > (StartAbortMenuTime+(F1_0*3))) rval = -2; net_udp_do_frame(0, 1); return rval; } int net_udp_endlevel(int *secret) { // Do whatever needs to be done between levels int i; // We do not really check if a player has actually found a secret level... yeah, I am too lazy! So just go there and pretend we did! for (i = 0; i < N_secret_levels; i++) { if (Current_level_num == Secret_level_table[i]) { *secret = 1; break; } } Network_status = NETSTAT_ENDLEVEL; // We are between levels net_udp_listen(); net_udp_send_endlevel_packet(); for (i=0; igame_status == NETSTAT_STARTING) return 1; if (game->game_status != NETSTAT_PLAYING) return 0; // Game is in progress, figure out if this guy can re-join it num_players = game->numplayers; if (!(game->game_flags & NETGAME_FLAG_CLOSED)) { // Look for player that is not connected if (game->numconnected==game->max_numplayers) return (2); if (game->RefusePlayers) return (3); if (game->numplayers < game->max_numplayers) return 1; if (game->numconnectedplayers[i].callsign)) && game->players[i].protocol.udp.isyou ) break; if (i != num_players) return 1; return 0; } // do UDP stuff to disconnect a player. Should ONLY be called from multi_disconnect_player() void net_udp_disconnect_player(int playernum) { // A player has disconnected from the net game, take whatever steps are // necessary if (playernum == Player_num) { Int3(); // Weird, see Rob return; } if (VerifyPlayerJoined==playernum) VerifyPlayerJoined=-1; net_udp_noloss_clear_mdata_got(playernum); } void net_udp_new_player(UDP_sequence_packet *their) { int pnum; pnum = their->player.connected; Assert(pnum >= 0); Assert(pnum < Netgame.max_numplayers); if (Newdemo_state == ND_STATE_RECORDING) { int new_player; if (pnum == N_players) new_player = 1; else new_player = 0; newdemo_record_multi_connect(pnum, new_player, their->player.callsign); } memcpy(Players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1); memcpy(Netgame.players[pnum].callsign, their->player.callsign, CALLSIGN_LEN+1); memcpy(&Netgame.players[pnum].protocol.udp.addr, &their->player.protocol.udp.addr, sizeof(struct _sockaddr)); ClipRank (&their->player.rank); Netgame.players[pnum].rank=their->player.rank; Players[pnum].connected = CONNECT_PLAYING; Players[pnum].net_kills_total = 0; Players[pnum].net_killed_total = 0; memset(kill_matrix[pnum], 0, MAX_PLAYERS*sizeof(short)); Players[pnum].score = 0; Players[pnum].flags = 0; Players[pnum].KillGoalCount=0; if (pnum == N_players) { N_players++; Netgame.numplayers = N_players; } digi_play_sample(SOUND_HUD_MESSAGE, F1_0); ClipRank (&their->player.rank); if (PlayerCfg.NoRankings) HUD_init_message(HM_MULTI, "'%s' %s\n",their->player.callsign, TXT_JOINING); else HUD_init_message(HM_MULTI, "%s'%s' %s\n",RankStrings[their->player.rank],their->player.callsign, TXT_JOINING); multi_make_ghost_player(pnum); multi_send_score(); net_udp_noloss_clear_mdata_got(pnum); } void net_udp_welcome_player(UDP_sequence_packet *their) { // Add a player to a game already in progress int player_num; int i; // Don't accept new players if we're ending this level. Its safe to // ignore since they'll request again later if ((Endlevel_sequence) || (Control_center_destroyed)) { net_udp_dump_player(their->player.protocol.udp.addr, DUMP_ENDLEVEL); return; } if (Network_send_objects || Network_sending_extras) { // Ignore silently, we're already responding to someone and we can't // do more than one person at a time. If we don't dump them they will // re-request in a few seconds. return; } if (their->player.connected != Current_level_num) { net_udp_dump_player(their->player.protocol.udp.addr, DUMP_LEVEL); return; } player_num = -1; memset(&UDP_sync_player, 0, sizeof(UDP_sequence_packet)); Network_player_added = 0; for (i = 0; i < N_players; i++) { if ((!d_stricmp(Players[i].callsign, their->player.callsign )) && !memcmp((struct _sockaddr *)&their->player.protocol.udp.addr, (struct _sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr))) { player_num = i; break; } } if (player_num == -1) { // Player is new to this game if ( !(Netgame.game_flags & NETGAME_FLAG_CLOSED) && (N_players < Netgame.max_numplayers)) { // Add player in an open slot, game not full yet player_num = N_players; Network_player_added = 1; } else if (Netgame.game_flags & NETGAME_FLAG_CLOSED) { // Slots are open but game is closed net_udp_dump_player(their->player.protocol.udp.addr, DUMP_CLOSED); return; } else { // Slots are full but game is open, see if anyone is // disconnected and replace the oldest player with this new one int oldest_player = -1; fix64 oldest_time = timer_query(); int activeplayers = 0; Assert(N_players == Netgame.max_numplayers); for (i = 0; i < Netgame.numplayers; i++) if (Netgame.players[i].connected) activeplayers++; if (activeplayers == Netgame.max_numplayers) { // Game is full. net_udp_dump_player(their->player.protocol.udp.addr, DUMP_FULL); return; } for (i = 0; i < N_players; i++) { if ( (!Players[i].connected) && (Netgame.players[i].LastPacketTime < oldest_time)) { oldest_time = Netgame.players[i].LastPacketTime; oldest_player = i; } } if (oldest_player == -1) { // Everyone is still connected net_udp_dump_player(their->player.protocol.udp.addr, DUMP_FULL); return; } else { // Found a slot! player_num = oldest_player; Network_player_added = 1; } } } else { // Player is reconnecting if (Players[player_num].connected) { return; } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_reconnect(player_num); Network_player_added = 0; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); if (PlayerCfg.NoRankings) HUD_init_message(HM_MULTI, "'%s' %s", Players[player_num].callsign, TXT_REJOIN); else HUD_init_message(HM_MULTI, "%s'%s' %s", RankStrings[Netgame.players[player_num].rank],Players[player_num].callsign, TXT_REJOIN); multi_send_score(); net_udp_noloss_clear_mdata_got(player_num); } Players[player_num].KillGoalCount=0; // Send updated Objects data to the new/returning player UDP_sync_player = *their; UDP_sync_player.player.connected = player_num; Network_send_objects = 1; Network_send_objnum = -1; Netgame.players[player_num].LastPacketTime = timer_query(); net_udp_send_objects(); } int net_udp_objnum_is_past(int objnum) { // determine whether or not a given object number has already been sent // to a re-joining player. int player_num = UDP_sync_player.player.connected; int obj_mode = !((object_owner[objnum] == -1) || (object_owner[objnum] == player_num)); if (!Network_send_objects) return 0; // We're not sending objects to a new player if (obj_mode > Network_send_object_mode) return 0; else if (obj_mode < Network_send_object_mode) return 1; else if (objnum < Network_send_objnum) return 1; else return 0; } void net_udp_send_door_updates(void) { // Send door status when new player joins int i; for (i = 0; i < Num_walls; i++) { if ((Walls[i].type == WALL_DOOR) && ((Walls[i].state == WALL_DOOR_OPENING) || (Walls[i].state == WALL_DOOR_WAITING))) multi_send_door_open(Walls[i].segnum, Walls[i].sidenum,0); else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].flags & WALL_BLASTED)) multi_send_door_open(Walls[i].segnum, Walls[i].sidenum,0); else if ((Walls[i].type == WALL_BLASTABLE) && (Walls[i].hps != WALL_HPS)) multi_send_hostage_door_status(i); } } void net_udp_process_monitor_vector(int vector) { int i, j; int count = 0; segment *seg; for (i=0; i <= Highest_segment_index; i++) { int tm, ec, bm; seg = &Segments[i]; for (j = 0; j < 6; j++) { if ( ((tm = seg->sides[j].tmap_num2) != 0) && ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) && ((bm = Effects[ec].dest_bm_num) != -1) ) { if (vector & (1 << count)) { seg->sides[j].tmap_num2 = bm | (tm&0xc000); } count++; Assert(count < 32); } } } } int net_udp_create_monitor_vector(void) { int i, j, k; int num_blown_bitmaps = 0; int monitor_num = 0; int blown_bitmaps[7]; int vector = 0; segment *seg; for (i=0; i < Num_effects; i++) { if (Effects[i].dest_bm_num > 0) { for (j = 0; j < num_blown_bitmaps; j++) if (blown_bitmaps[j] == Effects[i].dest_bm_num) break; if (j == num_blown_bitmaps) blown_bitmaps[num_blown_bitmaps++] = Effects[i].dest_bm_num; } } Assert(num_blown_bitmaps <= 7); for (i=0; i <= Highest_segment_index; i++) { int tm, ec; seg = &Segments[i]; for (j = 0; j < 6; j++) { if ((tm = seg->sides[j].tmap_num2) != 0) { if ( ((ec = TmapInfo[tm&0x3fff].eclip_num) != -1) && (Effects[ec].dest_bm_num != -1) ) { monitor_num++; Assert(monitor_num < 32); } else { for (k = 0; k < num_blown_bitmaps; k++) { if ((tm&0x3fff) == blown_bitmaps[k]) { vector |= (1 << monitor_num); monitor_num++; Assert(monitor_num < 32); break; } } } } } } return(vector); } void net_udp_stop_resync(UDP_sequence_packet *their) { if ( (!memcmp((struct _sockaddr *)&UDP_sync_player.player.protocol.udp.addr, (struct _sockaddr *)&their->player.protocol.udp.addr, sizeof(struct _sockaddr))) && (!d_stricmp(UDP_sync_player.player.callsign, their->player.callsign)) ) { Network_send_objects = 0; Network_sending_extras=0; Network_rejoined=0; Player_joining_extras=-1; Network_send_objnum = -1; } } ubyte object_buffer[UPID_MAX_SIZE]; void net_udp_send_objects(void) { sbyte owner, player_num = UDP_sync_player.player.connected; static int obj_count = 0; int loc = 0, i = 0, remote_objnum = 0, obj_count_frame = 0; static fix64 last_send_time = 0; if (last_send_time + (F1_0/50) > timer_query()) return; last_send_time = timer_query(); // Send clear objects array trigger and send player num Assert(Network_send_objects != 0); Assert(player_num >= 0); Assert(player_num < Netgame.max_numplayers); if (Endlevel_sequence || Control_center_destroyed) { // Endlevel started before we finished sending the goods, we'll // have to stop and try again after the level. net_udp_dump_player(UDP_sync_player.player.protocol.udp.addr, DUMP_ENDLEVEL); Network_send_objects = 0; return; } memset(object_buffer, 0, UPID_MAX_SIZE); object_buffer[0] = UPID_OBJECT_DATA; loc = 5; if (Network_send_objnum == -1) { obj_count = 0; Network_send_object_mode = 0; PUT_INTEL_INT(object_buffer+loc, -1); loc += 4; object_buffer[loc] = player_num; loc += 1; /* Placeholder for remote_objnum, not used here */ loc += 4; Network_send_objnum = 0; obj_count_frame = 1; } for (i = Network_send_objnum; i <= Highest_object_index; i++) { if ((Objects[i].type != OBJ_POWERUP) && (Objects[i].type != OBJ_PLAYER) && (Objects[i].type != OBJ_CNTRLCEN) && (Objects[i].type != OBJ_GHOST) && (Objects[i].type != OBJ_ROBOT) && (Objects[i].type != OBJ_HOSTAGE)) continue; if ((Network_send_object_mode == 0) && ((object_owner[i] != -1) && (object_owner[i] != player_num))) continue; if ((Network_send_object_mode == 1) && ((object_owner[i] == -1) || (object_owner[i] == player_num))) continue; if ( loc + sizeof(object_rw) + 9 > UPID_MAX_SIZE-1 ) break; // Not enough room for another object obj_count_frame++; obj_count++; remote_objnum = objnum_local_to_remote(i, &owner); Assert(owner == object_owner[i]); PUT_INTEL_INT(object_buffer+loc, i); loc += 4; object_buffer[loc] = owner; loc += 1; PUT_INTEL_INT(object_buffer+loc, remote_objnum); loc += 4; // use object_rw to send objects for now. if object sometime contains some day contains something useful the client should know about, we should use it. but by now it's also easier to use object_rw because then we also do not need fix64 timer values. multi_object_to_object_rw(&Objects[i], (object_rw *)&object_buffer[loc]); #ifdef WORDS_BIGENDIAN object_rw_swap((object_rw *)&object_buffer[loc], 1); #endif loc += sizeof(object_rw); } if (obj_count_frame) // Send any objects we've buffered { Network_send_objnum = i; PUT_INTEL_INT(object_buffer+1, obj_count_frame); Assert(loc <= UPID_MAX_SIZE); dxx_sendto (UDP_Socket[0], object_buffer, loc, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); } if (i > Highest_object_index) { if (Network_send_object_mode == 0) { Network_send_objnum = 0; Network_send_object_mode = 1; // go to next mode } else { Assert(Network_send_object_mode == 1); // Send count so other side can make sure he got them all object_buffer[0] = UPID_OBJECT_DATA; PUT_INTEL_INT(object_buffer+1, 1); PUT_INTEL_INT(object_buffer+5, -2); object_buffer[9] = player_num; PUT_INTEL_INT(object_buffer+10, obj_count); dxx_sendto (UDP_Socket[0], object_buffer, 14, 0, (struct sockaddr *)&UDP_sync_player.player.protocol.udp.addr, sizeof(struct _sockaddr)); // Send sync packet which tells the player who he is and to start! net_udp_send_rejoin_sync(player_num); // Turn off send object mode Network_send_objnum = -1; Network_send_objects = 0; obj_count = 0; Network_sending_extras=3; // start to send extras VerifyPlayerJoined = Player_joining_extras = player_num; return; } // mode == 1; } // i > Highest_object_index } int net_udp_verify_objects(int remote, int local) { int i, nplayers = 0; if ((remote-local) > 10) return(2); for (i = 0; i <= Highest_object_index; i++) { if ((Objects[i].type == OBJ_PLAYER) || (Objects[i].type == OBJ_GHOST)) nplayers++; } if (Netgame.max_numplayers<=nplayers) return(0); return(1); } void net_udp_read_object_packet( ubyte *data ) { // Object from another net player we need to sync with object *obj; sbyte obj_owner; static int mode = 0, object_count = 0, my_pnum = 0; int i = 0, segnum = 0, objnum = 0, remote_objnum = 0, nobj = 0, loc = 5; nobj = GET_INTEL_INT(data + 1); for (i = 0; i < nobj; i++) { objnum = GET_INTEL_INT(data + loc); loc += 4; obj_owner = data[loc]; loc += 1; remote_objnum = GET_INTEL_INT(data + loc); loc += 4; if (objnum == -1) { // Clear object array init_objects(); Network_rejoined = 1; my_pnum = obj_owner; change_playernum_to(my_pnum); mode = 1; object_count = 0; } else if (objnum == -2) { // Special debug checksum marker for entire send if (mode == 1) { special_reset_objects(); mode = 0; } if (remote_objnum != object_count) { Int3(); } if (net_udp_verify_objects(remote_objnum, object_count)) { // Failed to sync up nm_messagebox(NULL, 1, TXT_OK, TXT_NET_SYNC_FAILED); Network_status = NETSTAT_MENU; return; } } else { object_count++; if ((obj_owner == my_pnum) || (obj_owner == -1)) { if (mode != 1) Int3(); // SEE ROB objnum = remote_objnum; } else { if (mode == 1) { special_reset_objects(); mode = 0; } objnum = obj_allocate(); } if (objnum != -1) { obj = &Objects[objnum]; if (obj->segnum != -1) obj_unlink(objnum); Assert(obj->segnum == -1); Assert(objnum < MAX_OBJECTS); #ifdef WORDS_BIGENDIAN object_rw_swap((object_rw *)&data[loc], 1); #endif multi_object_rw_to_object((object_rw *)&data[loc], obj); loc += sizeof(object_rw); segnum = obj->segnum; obj->next = obj->prev = obj->segnum = -1; obj->attached_obj = -1; if (segnum > -1) obj_link(obj-Objects,segnum); if (obj_owner == my_pnum) map_objnum_local_to_local(objnum); else if (obj_owner != -1) map_objnum_local_to_remote(objnum, remote_objnum, obj_owner); else object_owner[objnum] = -1; } } // For a standard onbject } // For each object in packet } void net_udp_send_rejoin_sync(int player_num) { int i, j; Players[player_num].connected = CONNECT_PLAYING; // connect the new guy Netgame.players[player_num].LastPacketTime = timer_query(); if (Endlevel_sequence || Control_center_destroyed) { // Endlevel started before we finished sending the goods, we'll // have to stop and try again after the level. net_udp_dump_player(UDP_sync_player.player.protocol.udp.addr, DUMP_ENDLEVEL); Network_send_objects = 0; Network_sending_extras=0; return; } if (Network_player_added) { UDP_sync_player.type = UPID_ADDPLAYER; UDP_sync_player.player.connected = player_num; net_udp_new_player(&UDP_sync_player); for (i = 0; i < N_players; i++) { if ((i != player_num) && (i != Player_num) && (Players[i].connected)) net_udp_send_sequence_packet( UDP_sync_player, Netgame.players[i].protocol.udp.addr); } } // Send sync packet to the new guy net_udp_update_netgame(); // Fill in the kill list for (j=0; j= MAX_PLAYERS ) return NULL; if ( Objects[objnum].id >= N_players ) return NULL; return Players[Objects[objnum].id].callsign; } void net_udp_add_player(UDP_sequence_packet *p) { int i; for (i=0; iplayer.protocol.udp.addr, sizeof(struct _sockaddr))) { Netgame.players[i].LastPacketTime = timer_query(); return; // already got them } } if ( N_players >= MAX_PLAYERS ) { return; // too many of em } ClipRank (&p->player.rank); memcpy( Netgame.players[N_players].callsign, p->player.callsign, CALLSIGN_LEN+1 ); memcpy( (struct _sockaddr *)&Netgame.players[N_players].protocol.udp.addr, (struct _sockaddr *)&p->player.protocol.udp.addr, sizeof(struct _sockaddr) ); Netgame.players[N_players].rank=p->player.rank; Netgame.players[N_players].connected = CONNECT_PLAYING; Players[N_players].KillGoalCount=0; Players[N_players].connected = CONNECT_PLAYING; Netgame.players[N_players].LastPacketTime = timer_query(); N_players++; Netgame.numplayers = N_players; net_udp_send_netgame_update(); } // One of the players decided not to join the game void net_udp_remove_player(UDP_sequence_packet *p) { int i,pn; pn = -1; for (i=0; iplayer.protocol.udp.addr, sizeof(struct _sockaddr))) { pn = i; break; } } if (pn < 0 ) return; for (i=pn; i DUMP_LEVEL) // invalid dump... heh break; Network_status = NETSTAT_MENU; // stop us from sending before message nm_messagebox(NULL, 1, TXT_OK, NET_DUMP_STRINGS(data[1])); Network_status = NETSTAT_MENU; multi_reset_stuff(); break; } } void net_udp_process_request(UDP_sequence_packet *their) { // Player is ready to receieve a sync packet int i; for (i = 0; i < N_players; i++) if (!memcmp((struct _sockaddr *)&their->player.protocol.udp.addr, (struct _sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)) && (!d_stricmp(their->player.callsign, Netgame.players[i].callsign))) { Players[i].connected = CONNECT_PLAYING; Netgame.players[i].LastPacketTime = timer_query(); break; } } void net_udp_process_packet(ubyte *data, struct _sockaddr sender_addr, int length ) { UDP_sequence_packet their; memset(&their, 0, sizeof(UDP_sequence_packet)); switch (data[0]) { case UPID_VERSION_DENY: if (multi_i_am_master() || length != UPID_VERSION_DENY_SIZE) break; net_udp_process_version_deny(data, sender_addr); break; case UPID_GAME_INFO_REQ: { int result = 0; static fix64 last_full_req_time = 0; if (!multi_i_am_master() || length != UPID_GAME_INFO_REQ_SIZE) break; if (timer_query() < last_full_req_time+(F1_0/2)) // answer 2 times per second max break; last_full_req_time = timer_query(); result = net_udp_check_game_info_request(data, 0); if (result == -1) net_udp_send_version_deny(sender_addr); else if (result == 1) net_udp_send_game_info(sender_addr, UPID_GAME_INFO); break; } case UPID_GAME_INFO: if (multi_i_am_master() || length != UPID_GAME_INFO_SIZE) break; net_udp_process_game_info(data, length, sender_addr, 0); break; case UPID_GAME_INFO_LITE_REQ: { static fix64 last_lite_req_time = 0; if (!multi_i_am_master() || length != UPID_GAME_INFO_LITE_REQ_SIZE) break; if (timer_query() < last_lite_req_time+(F1_0/8))// answer 8 times per second max break; last_lite_req_time = timer_query(); if (net_udp_check_game_info_request(data, 1) == 1) net_udp_send_game_info(sender_addr, UPID_GAME_INFO_LITE); break; } case UPID_GAME_INFO_LITE: if (multi_i_am_master() || length != UPID_GAME_INFO_LITE_SIZE) break; net_udp_process_game_info(data, length, sender_addr, 1); break; case UPID_DUMP: if (multi_i_am_master() || memcmp((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr)) || length != UPID_DUMP_SIZE) break; if ((Network_status == NETSTAT_WAITING) || (Network_status == NETSTAT_PLAYING)) net_udp_process_dump(data, length, sender_addr); break; case UPID_ADDPLAYER: if (multi_i_am_master() || memcmp((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr)) || length != UPID_SEQUENCE_SIZE) break; net_udp_receive_sequence_packet(data, &their, sender_addr); net_udp_new_player(&their); break; case UPID_REQUEST: if (!multi_i_am_master() || length != UPID_SEQUENCE_SIZE) break; net_udp_receive_sequence_packet(data, &their, sender_addr); if (Network_status == NETSTAT_STARTING) { // Someone wants to join our game! net_udp_add_player(&their); } else if (Network_status == NETSTAT_WAITING) { // Someone is ready to recieve a sync packet net_udp_process_request(&their); } else if (Network_status == NETSTAT_PLAYING) { // Someone wants to join a game in progress! if (Netgame.RefusePlayers) net_udp_do_refuse_stuff (&their); else net_udp_welcome_player(&their); } break; case UPID_QUIT_JOINING: if (!multi_i_am_master() || length != UPID_SEQUENCE_SIZE) break; net_udp_receive_sequence_packet(data, &their, sender_addr); if (Network_status == NETSTAT_STARTING) net_udp_remove_player( &their ); else if ((Network_status == NETSTAT_PLAYING) && (Network_send_objects)) net_udp_stop_resync( &their ); break; case UPID_SYNC: if (multi_i_am_master() || length != UPID_GAME_INFO_SIZE || Network_status != NETSTAT_WAITING) break; net_udp_read_sync_packet(data, length, sender_addr); break; case UPID_OBJECT_DATA: if (multi_i_am_master() || length > UPID_MAX_SIZE || Network_status != NETSTAT_WAITING) break; net_udp_read_object_packet(data); break; case UPID_PING: if (multi_i_am_master() || length != UPID_PING_SIZE) break; net_udp_process_ping(data, length, sender_addr); break; case UPID_PONG: if (!multi_i_am_master() || length != UPID_PONG_SIZE) break; net_udp_process_pong(data, length, sender_addr); break; case UPID_ENDLEVEL_H: if ((!multi_i_am_master()) && ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))) net_udp_read_endlevel_packet( data, length, sender_addr ); break; case UPID_ENDLEVEL_C: if ((multi_i_am_master()) && ((Network_status == NETSTAT_ENDLEVEL) || (Network_status == NETSTAT_PLAYING))) net_udp_read_endlevel_packet( data, length, sender_addr ); break; case UPID_PDATA: net_udp_process_pdata( data, length, sender_addr ); break; case UPID_MDATA_PNORM: net_udp_process_mdata( data, length, sender_addr, 0 ); break; case UPID_MDATA_PNEEDACK: net_udp_process_mdata( data, length, sender_addr, 1 ); break; case UPID_MDATA_ACK: net_udp_noloss_got_ack(data, length); break; #ifdef USE_TRACKER case UPID_TRACKER_VERIFY: iTrackerVerified = 1; break; case UPID_TRACKER_INCGAME: udp_tracker_process_game( data, length ); break; #endif default: con_printf(CON_DEBUG, "unknown packet type received - type %i\n", data[0]); break; } } // Packet for end of level syncing void net_udp_read_endlevel_packet( ubyte *data, int data_len, struct _sockaddr sender_addr ) { int len = 0, i = 0, j = 0; ubyte tmpvar = 0; if (multi_i_am_master()) { ubyte pnum = data[1]; if (memcmp((struct _sockaddr *)&Netgame.players[pnum].protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr))) return; len += 2; if ((int)data[len] == CONNECT_DISCONNECTED) multi_disconnect_player(pnum); Players[pnum].connected = data[len]; len++; tmpvar = data[len]; len++; if ((Network_status != NETSTAT_PLAYING) && (Players[pnum].connected == CONNECT_PLAYING) && (tmpvar < Countdown_seconds_left)) Countdown_seconds_left = tmpvar; Players[pnum].net_kills_total = GET_INTEL_SHORT(&(data[len])); len += 2; Players[pnum].net_killed_total = GET_INTEL_SHORT(&(data[len])); len += 2; for (i = 0; i < MAX_PLAYERS; i++) { kill_matrix[pnum][i] = GET_INTEL_SHORT(&(data[len])); len += 2; } if (Players[pnum].connected) Netgame.players[pnum].LastPacketTime = timer_query(); } else { if (memcmp((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr))) return; len++; tmpvar = data[len]; len++; if ((Network_status != NETSTAT_PLAYING) && (tmpvar < Countdown_seconds_left)) Countdown_seconds_left = tmpvar; for (i = 0; i < MAX_PLAYERS; i++) { if (i == Player_num) { len += 5; continue; } if ((int)data[len] == CONNECT_DISCONNECTED) multi_disconnect_player(i); Players[i].connected = data[len]; len++; Players[i].net_kills_total = GET_INTEL_SHORT(&(data[len])); len += 2; Players[i].net_killed_total = GET_INTEL_SHORT(&(data[len])); len += 2; if (Players[i].connected) Netgame.players[i].LastPacketTime = timer_query(); } for (i = 0; i < MAX_PLAYERS; i++) { for (j = 0; j < MAX_PLAYERS; j++) { if (i != Player_num) { kill_matrix[i][j] = GET_INTEL_SHORT(&(data[len])); } len += 2; } } } } /* * Polling loop waiting for sync packet to start game after having sent request */ int net_udp_sync_poll( newmenu *menu, d_event *event, void *userdata ) { static fix64 t1 = 0; int rval = 0; if (event->type != EVENT_WINDOW_DRAW) return 0; menu = menu; userdata = userdata; net_udp_listen(); // Leave if Host disconnects if (Netgame.players[0].connected == CONNECT_DISCONNECTED) rval = -2; if (Network_status != NETSTAT_WAITING) // Status changed to playing, exit the menu rval = -2; if (Network_status != NETSTAT_MENU && !Network_rejoined && (timer_query() > t1+F1_0*2)) { int i; // Poll time expired, re-send request t1 = timer_query(); i = net_udp_send_request(); if (i < 0) rval = -2; } return rval; } int net_udp_start_poll( newmenu *menu, d_event *event, void *userdata ) { newmenu_item *menus = newmenu_get_items(menu); int nitems = newmenu_get_nitems(menu); int i,n,nm; if (event->type != EVENT_WINDOW_DRAW) return 0; userdata = userdata; Assert(Network_status == NETSTAT_STARTING); if (!menus[0].value) { menus[0].value = 1; } for (i=1; i= N_players) && (menus[i].value) ) { menus[i].value = 0; } } nm = 0; for (i=0; i N_players ) { menus[i].value = 0; } } } if ( nm > Netgame.max_numplayers ) { nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, Netgame.max_numplayers, TXT_NETPLAYERS_IN ); // Turn off the last player highlighted for (i = N_players; i > 0; i--) if (menus[i].value == 1) { menus[i].value = 0; break; } } //added/killed by Victor Rachels to eventually add msging //since nitems should not be changing, anyway // if (nitems > MAX_PLAYERS ) return; //end this section kill - VR n = Netgame.numplayers; net_udp_listen(); if (n < Netgame.numplayers ) { if (PlayerCfg.NoRankings) sprintf( menus[N_players-1].text, "%d. %-20s", N_players,Netgame.players[N_players-1].callsign ); else sprintf( menus[N_players-1].text, "%d. %s%-20s", N_players, RankStrings[Netgame.players[N_players-1].rank],Netgame.players[N_players-1].callsign ); //Begin addition by GF digi_play_sample(SOUND_HUD_MESSAGE, F1_0); //A noise to alert you when someone joins a starting game... //End addition by GF if (N_players <= Netgame.max_numplayers) { menus[N_players-1].value = 1; } } else if ( n > Netgame.numplayers ) { // One got removed... //Begin addition by GF // digi_play_sample(SOUND_HUD_KILL, F1_0); //A noise to alert you when someone leaves a starting game... //End addition by GF for (i=0; i> i) & 1; } newmenu_do1( NULL, "Objects to allow", MULTI_ALLOW_POWERUP_MAX, m, NULL, NULL, 0 ); Netgame.AllowedItems &= ~NETFLAG_DOPOWERUP; for (i = 0; i < MULTI_ALLOW_POWERUP_MAX; i++) if (m[i].value) Netgame.AllowedItems |= (1 << i); } int net_udp_more_options_handler( newmenu *menu, d_event *event, void *userdata ); void net_udp_more_game_options () { int opt=0,i=0; char PlayText[80],KillText[80],srinvul[50],packstring[5]; #ifdef USE_TRACKER newmenu_item m[16]; #else newmenu_item m[15]; #endif snprintf(packstring,sizeof(char)*4,"%d",Netgame.PacketsPerSec); opt_difficulty = opt; m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.difficulty; m[opt].text=TXT_DIFFICULTY; m[opt].min_value=0; m[opt].max_value=(NDL-1); opt++; opt_cinvul = opt; sprintf( srinvul, "%s: %d %s", TXT_REACTOR_LIFE, Netgame.control_invul_time/F1_0/60, TXT_MINUTES_ABBREV ); m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.control_invul_time/5/F1_0/60; m[opt].text= srinvul; m[opt].min_value=0; m[opt].max_value=10; opt++; opt_playtime=opt; sprintf( PlayText, "Max time: %d %s", Netgame.PlayTimeAllowed*5, TXT_MINUTES_ABBREV ); m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.PlayTimeAllowed; m[opt].text= PlayText; m[opt].min_value=0; m[opt].max_value=10; opt++; opt_killgoal=opt; sprintf( KillText, "Kill Goal: %d kills", Netgame.KillGoal*5); m[opt].type = NM_TYPE_SLIDER; m[opt].value=Netgame.KillGoal; m[opt].text= KillText; m[opt].min_value=0; m[opt].max_value=10; opt++; opt_show_on_map=opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = TXT_SHOW_ON_MAP; m[opt].value=(Netgame.game_flags & NETGAME_FLAG_SHOW_MAP); opt_show_on_map=opt; opt++; opt_start_invul=opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "Invulnerable when reappearing"; m[opt].value=Netgame.InvulAppear; opt++; opt_bright = opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "Bright player ships"; m[opt].value=Netgame.BrightPlayers; opt++; opt_show_names=opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "Show enemy names on HUD"; m[opt].value=Netgame.ShowEnemyNames; opt++; opt_ffire=opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "No friendly fire (Team, Coop)"; m[opt].value=Netgame.NoFriendlyFire; opt++; opt_setpower = opt; m[opt].type = NM_TYPE_MENU; m[opt].text = "Set Objects allowed..."; opt++; m[opt].type = NM_TYPE_TEXT; m[opt].text = "Packets per second (2 - 20)"; opt++; opt_packets=opt; m[opt].type = NM_TYPE_INPUT; m[opt].text=packstring; m[opt].text_len=2; opt++; opt_shortpack=opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "Short Packets (saves traffic)"; m[opt].value = Netgame.ShortPackets; opt++; m[opt].type = NM_TYPE_TEXT; m[opt].text = "Network port"; opt++; opt_port = opt; m[opt].type = NM_TYPE_INPUT; m[opt].text = UDP_MyPort; m[opt].text_len=5; opt++; #ifdef USE_TRACKER opt_tracker = opt; m[opt].type = NM_TYPE_CHECK; m[opt].text = "Track this game"; m[opt].value = Netgame.Tracker; opt++; #endif menu: i = newmenu_do1( NULL, "Advanced netgame options", opt, m, net_udp_more_options_handler, NULL, 0 ); Netgame.control_invul_time = m[opt_cinvul].value*5*F1_0*60; if (i==opt_setpower) { net_udp_set_power (); goto menu; } Netgame.PacketsPerSec=atoi(packstring); if (Netgame.PacketsPerSec>20) { Netgame.PacketsPerSec=20; nm_messagebox(TXT_ERROR, 1, TXT_OK, "Packet value out of range\nSetting value to 20"); } if (Netgame.PacketsPerSec<2) { nm_messagebox(TXT_ERROR, 1, TXT_OK, "Packet value out of range\nSetting value to 2"); Netgame.PacketsPerSec=2; } Netgame.ShortPackets=m[opt_shortpack].value; if ((atoi(UDP_MyPort)) < 0 ||(atoi(UDP_MyPort)) > 65535) { snprintf (UDP_MyPort, sizeof(UDP_MyPort), "%d", UDP_PORT_DEFAULT); nm_messagebox(TXT_ERROR, 1, TXT_OK, "Illegal port"); } Netgame.InvulAppear=m[opt_start_invul].value; Netgame.BrightPlayers=m[opt_bright].value; Netgame.ShowEnemyNames=m[opt_show_names].value; Netgame.difficulty=Difficulty_level = m[opt_difficulty].value; if (m[opt_show_on_map].value) Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP; else Netgame.game_flags &= ~NETGAME_FLAG_SHOW_MAP; Netgame.NoFriendlyFire = m[opt_ffire].value; #ifdef USE_TRACKER Netgame.Tracker = m[opt_tracker].value; #endif } int net_udp_more_options_handler( newmenu *menu, d_event *event, void *userdata ) { newmenu_item *menus = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); switch (event->type) { case EVENT_NEWMENU_CHANGED: if (citem == opt_cinvul) sprintf( menus[opt_cinvul].text, "%s: %d %s", TXT_REACTOR_LIFE, menus[opt_cinvul].value*5, TXT_MINUTES_ABBREV ); else if (citem == opt_playtime) { if (Game_mode & GM_MULTI_COOP) { nm_messagebox ("Sorry",1,TXT_OK,"You can't change those for coop!"); menus[opt_playtime].value=0; return 0; } Netgame.PlayTimeAllowed=menus[opt_playtime].value; sprintf( menus[opt_playtime].text, "Max Time: %d %s", Netgame.PlayTimeAllowed*5, TXT_MINUTES_ABBREV ); } else if (citem == opt_killgoal) { if (Game_mode & GM_MULTI_COOP) { nm_messagebox ("Sorry",1,TXT_OK,"You can't change those for coop!"); menus[opt_killgoal].value=0; return 0; } Netgame.KillGoal=menus[opt_killgoal].value; sprintf( menus[opt_killgoal].text, "Kill Goal: %d kills", Netgame.KillGoal*5); } break; default: break; } userdata = userdata; return 0; } typedef struct param_opt { int start_game, name, level, mode, mode_end, moreopts; int closed, refuse, maxnet, anarchy, team_anarchy, robot_anarchy, coop, bounty; } param_opt; int net_udp_start_game(void); int net_udp_game_param_handler( newmenu *menu, d_event *event, param_opt *opt ) { newmenu_item *menus = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); switch (event->type) { case EVENT_NEWMENU_CHANGED: if (citem == opt->team_anarchy) { menus[opt->closed].value = 1; menus[opt->closed-1].value = 0; menus[opt->closed+1].value = 0; } if (menus[opt->coop].value) { if (menus[opt->maxnet].value>2) { menus[opt->maxnet].value=2; } if (menus[opt->maxnet].max_value>2) { menus[opt->maxnet].max_value=2; } sprintf( menus[opt->maxnet].text, "Maximum players: %d", menus[opt->maxnet].value+2 ); Netgame.max_numplayers = menus[opt->maxnet].value+2; if (!(Netgame.game_flags & NETGAME_FLAG_SHOW_MAP)) Netgame.game_flags |= NETGAME_FLAG_SHOW_MAP; if (Netgame.PlayTimeAllowed || Netgame.KillGoal) { Netgame.PlayTimeAllowed=0; Netgame.KillGoal=0; } } else // if !Coop game { if (menus[opt->maxnet].max_value<6) { menus[opt->maxnet].value=6; menus[opt->maxnet].max_value=6; sprintf( menus[opt->maxnet].text, "Maximum players: %d", menus[opt->maxnet].value+2 ); Netgame.max_numplayers = menus[opt->maxnet].value+2; } } if (citem == opt->level) { char *slevel = menus[opt->level].text; Netgame.levelnum = atoi(slevel); if (!d_strnicmp(slevel, "s", 1)) Netgame.levelnum = -atoi(slevel+1); else Netgame.levelnum = atoi(slevel); // if ((Netgame.levelnum < Last_secret_level) || (Netgame.levelnum > Last_level) || (Netgame.levelnum == 0)) // { // nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE ); // sprintf(slevel, "1"); // return 0; // } } if (citem == opt->maxnet) { sprintf( menus[opt->maxnet].text, "Maximum players: %d", menus[opt->maxnet].value+2 ); Netgame.max_numplayers = menus[opt->maxnet].value+2; } if ((citem >= opt->mode) && (citem <= opt->mode_end)) { if ( menus[opt->anarchy].value ) Netgame.gamemode = NETGAME_ANARCHY; else if (menus[opt->team_anarchy].value) { Netgame.gamemode = NETGAME_TEAM_ANARCHY; } // else if (ANARCHY_ONLY_MISSION) { // int i = 0; // nm_messagebox(NULL, 1, TXT_OK, TXT_ANARCHY_ONLY_MISSION); // for (i = opt->mode; i <= opt->mode_end; i++) // menus[i].value = 0; // menus[opt->anarchy].value = 1; // return 0; // } else if ( menus[opt->robot_anarchy].value ) Netgame.gamemode = NETGAME_ROBOT_ANARCHY; else if ( menus[opt->coop].value ) Netgame.gamemode = NETGAME_COOPERATIVE; else if ( menus[opt->bounty].value ) Netgame.gamemode = NETGAME_BOUNTY; else Int3(); // Invalid mode -- see Rob } if (menus[opt->closed].value) Netgame.game_flags |= NETGAME_FLAG_CLOSED; else Netgame.game_flags &= ~NETGAME_FLAG_CLOSED; Netgame.RefusePlayers=menus[opt->refuse].value; break; case EVENT_NEWMENU_SELECTED: if ((Netgame.levelnum < Last_secret_level) || (Netgame.levelnum > Last_level) || (Netgame.levelnum == 0)) { char *slevel = menus[opt->level].text; nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_LEVEL_OUT_RANGE ); sprintf(slevel, "1"); return 1; } if (citem==opt->moreopts) { if ( menus[opt->coop].value ) Game_mode=GM_MULTI_COOP; net_udp_more_game_options(); Game_mode=0; return 1; } if (citem==opt->start_game) return !net_udp_start_game(); return 1; default: break; } return 0; } int net_udp_setup_game() { int i; int optnum; param_opt opt; newmenu_item m[22]; char slevel[5]; char level_text[32]; char srmaxnet[50]; net_udp_init(); multi_new_game(); change_playernum_to(0); for (i=0;i= 0; } void net_udp_set_game_mode(int gamemode) { Show_kill_list = 1; if ( gamemode == NETGAME_ANARCHY ) Game_mode = GM_NETWORK; else if ( gamemode == NETGAME_ROBOT_ANARCHY ) Game_mode = GM_NETWORK | GM_MULTI_ROBOTS; else if ( gamemode == NETGAME_COOPERATIVE ) Game_mode = GM_NETWORK | GM_MULTI_COOP | GM_MULTI_ROBOTS; else if ( gamemode == NETGAME_TEAM_ANARCHY ) { Game_mode = GM_NETWORK | GM_TEAM; Show_kill_list = 3; } else if( gamemode == NETGAME_BOUNTY ) Game_mode = GM_NETWORK | GM_BOUNTY; else Int3(); } void net_udp_read_sync_packet( ubyte * data, int data_len, struct _sockaddr sender_addr ) { int i, j; char temp_callsign[CALLSIGN_LEN+1]; // This function is now called by all people entering the netgame. if (data) { net_udp_process_game_info(data, data_len, sender_addr, 0); } N_players = Netgame.numplayers; Difficulty_level = Netgame.difficulty; Network_status = Netgame.game_status; // New code, 11/27 if (Netgame.segments_checksum != my_segments_checksum) { Network_status = NETSTAT_MENU; nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_NETLEVEL_NMATCH); #ifdef NDEBUG return; #endif } // Discover my player number memcpy(temp_callsign, Players[Player_num].callsign, CALLSIGN_LEN+1); Player_num = -1; for (i=0; i 0) && (choice < opt_team_b)) { team_vector |= (1 << pnums[choice]); } else if ((choice > opt_team_b) && (choice < opt-2)) { team_vector &= ~(1 << pnums[choice]); } else if (choice == -1) return 0; goto menu; } int net_udp_select_players(void) { int i, j, opts, opt_msg; newmenu_item m[MAX_PLAYERS+1]; char text[MAX_PLAYERS][45]; char title[50]; int save_nplayers; net_udp_add_player( &UDP_Seq ); for (i=0; i< MAX_PLAYERS; i++ ) { sprintf( text[i], "%d. %-20s", i+1, "" ); m[i].type = NM_TYPE_CHECK; m[i].text = text[i]; m[i].value = 0; } //added/edited on 11/7/98 by Victor Rachels in an attempt to get msgs going. opts=MAX_PLAYERS; opt_msg = opts; //killed for now to not raise people's hopes - 11/10/98 - VR // m[opts].type = NM_TYPE_MENU; m[opts].text = "Send message..."; opts++; m[0].value = 1; // Assume server will play... if (PlayerCfg.NoRankings) sprintf( text[0], "%d. %-20s", 1, Players[Player_num].callsign ); else sprintf( text[0], "%d. %s%-20s", 1, RankStrings[Netgame.players[Player_num].rank],Players[Player_num].callsign ); sprintf( title, "%s %d %s", TXT_TEAM_SELECT, Netgame.max_numplayers, TXT_TEAM_PRESS_ENTER ); GetPlayersAgain: #ifdef USE_TRACKER if( Netgame.Tracker ) udp_tracker_register(); #endif j=opt_msg; while(j==opt_msg) { timer_update(); j=newmenu_do1( NULL, title, opts, m, net_udp_start_poll, NULL, 1 ); if(j==opt_msg) { multi_send_message_dialog(); if (Network_message_reciever != -1) multi_send_message(); } } //end this section addition save_nplayers = N_players; if (j<0) { // Aborted! // Dump all players and go back to menu mode #ifdef USE_TRACKER if( Netgame.Tracker ) udp_tracker_unregister(); #endif abort: // Tell everyone we're bailing Netgame.numplayers = 0; for (i=1; i Netgame.max_numplayers) { nm_messagebox( TXT_ERROR, 1, TXT_OK, "%s %d %s", TXT_SORRY_ONLY, Netgame.max_numplayers, TXT_NETPLAYERS_IN ); N_players = save_nplayers; goto GetPlayersAgain; } // Let host join without Client available. Let's see if our players like that #if 0 //def RELEASE if ( N_players < 2 ) { nm_messagebox( TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_TWO ); N_players = save_nplayers; goto GetPlayersAgain; } #endif // Let host join without Client available. Let's see if our players like that #if 0 //def RELEASE if ( (Netgame.gamemode == NETGAME_TEAM_ANARCHY) && (N_players < 3) ) { nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_TEAM_ATLEAST_THREE ); N_players = save_nplayers; goto GetPlayersAgain; } #endif // Remove players that aren't marked. N_players = 0; for (i=0; i N_players) { memcpy(Netgame.players[N_players].callsign, Netgame.players[i].callsign, CALLSIGN_LEN+1); Netgame.players[N_players].rank=Netgame.players[i].rank; ClipRank (&Netgame.players[N_players].rank); } Players[N_players].connected = CONNECT_PLAYING; N_players++; } else { net_udp_dump_player(Netgame.players[i].protocol.udp.addr, DUMP_DORK); } } for (i = N_players; i < MAX_PLAYERS; i++) { memset(Netgame.players[i].callsign, 0, CALLSIGN_LEN+1); Netgame.players[i].rank=0; } if (Netgame.gamemode == NETGAME_TEAM_ANARCHY) if (!net_udp_select_teams()) goto abort; return(1); } int net_udp_start_game(void) { int i; i = udp_open_socket(0, atoi(UDP_MyPort)); if (i != 0) return 0; if (atoi(UDP_MyPort) != UDP_PORT_DEFAULT) i = udp_open_socket(1, UDP_PORT_DEFAULT); // Default port open for Broadcasts if (i != 0) return 0; // prepare broadcast address to announce our game memset(&GBcast, '\0', sizeof(struct _sockaddr)); udp_dns_filladdr(UDP_BCAST_ADDR, UDP_PORT_DEFAULT, &GBcast); #ifdef IPv6 memset(&GMcast_v6, '\0', sizeof(struct _sockaddr)); udp_dns_filladdr(UDP_MCASTv6_ADDR, UDP_PORT_DEFAULT, &GMcast_v6); #endif d_srand( (fix)timer_query() ); Netgame.protocol.udp.GameID=d_rand(); N_players = 0; Netgame.game_status = NETSTAT_STARTING; Netgame.numplayers = 0; net_udp_set_game_mode(Netgame.gamemode); Netgame.players[0].protocol.udp.isyou = 1; // I am Host. I need to know that y'know? For syncing later. Network_status = NETSTAT_STARTING; if(net_udp_select_players()) { StartNewLevel(Netgame.levelnum); } else { Game_mode = GM_GAME_OVER; return 0; // see if we want to tweak the game we setup } net_udp_broadcast_game_info(UPID_GAME_INFO_LITE); // game started. broadcast our current status to everyone who wants to know return 1; // don't keep params menu or mission listbox (may want to join a game next time) } int net_udp_wait_for_sync(void) { char text[60]; newmenu_item m[2]; int i, choice=0; Network_status = NETSTAT_WAITING; m[0].type=NM_TYPE_TEXT; m[0].text = text; m[1].type=NM_TYPE_TEXT; m[1].text = TXT_NET_LEAVE; i = net_udp_send_request(); if (i < 0) return(-1); sprintf( m[0].text, "%s\n'%s' %s", TXT_NET_WAITING, Netgame.players[i].callsign, TXT_NET_TO_ENTER ); while (choice > -1) { timer_update(); choice=newmenu_do( NULL, TXT_WAIT, 2, m, net_udp_sync_poll, NULL ); } if (Network_status != NETSTAT_PLAYING) { UDP_sequence_packet me; memset(&me, 0, sizeof(UDP_sequence_packet)); me.type = UPID_QUIT_JOINING; memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 ); net_udp_send_sequence_packet( me, Netgame.players[0].protocol.udp.addr ); N_players = 0; Game_mode = GM_GAME_OVER; return(-1); // they cancelled } return(0); } int net_udp_request_poll( newmenu *menu, d_event *event, void *userdata ) { // Polling loop for waiting-for-requests menu int i = 0; int num_ready = 0; if (event->type != EVENT_WINDOW_DRAW) return 0; menu = menu; userdata = userdata; net_udp_listen(); net_udp_timeout_check(timer_query()); for (i = 0; i < N_players; i++) { if ((Players[i].connected == CONNECT_PLAYING) || (Players[i].connected == CONNECT_DISCONNECTED)) num_ready++; } if (num_ready == N_players) // All players have checked in or are disconnected { return -2; } return 0; } int net_udp_wait_for_requests(void) { // Wait for other players to load the level before we send the sync int choice, i; newmenu_item m[1]; Network_status = NETSTAT_WAITING; m[0].type=NM_TYPE_TEXT; m[0].text = TXT_NET_LEAVE; Network_status = NETSTAT_WAITING; net_udp_flush(); Players[Player_num].connected = CONNECT_PLAYING; menu: choice = newmenu_do(NULL, TXT_WAIT, 1, m, net_udp_request_poll, NULL); if (choice == -1) { // User aborted choice = nm_messagebox(NULL, 3, TXT_YES, TXT_NO, TXT_START_NOWAIT, TXT_QUITTING_NOW); if (choice == 2) return 0; if (choice != 0) goto menu; // User confirmed abort for (i=0; i < N_players; i++) if ((Players[i].connected != CONNECT_DISCONNECTED) && (i != Player_num)) net_udp_dump_player(Netgame.players[i].protocol.udp.addr, DUMP_ABORTED); return -1; } else if (choice != -2) goto menu; return 0; } int net_udp_level_sync(void) { // Do required syncing between (before) levels int result = 0; memset(&UDP_MData, 0, sizeof(UDP_mdata_info)); net_udp_noloss_init_mdata_queue(); // my_segments_checksum = netmisc_calc_checksum(Segments, sizeof(segment)*(Highest_segment_index+1)); net_udp_flush(); // Flush any old packets if (N_players == 0) result = net_udp_wait_for_sync(); else if (multi_i_am_master()) { result = net_udp_wait_for_requests(); if (!result) result = net_udp_send_sync(); } else result = net_udp_wait_for_sync(); multi_powcap_count_powerups_in_mine(); if (result) { Players[Player_num].connected = CONNECT_DISCONNECTED; net_udp_send_endlevel_packet(); if (Game_wind) window_close(Game_wind); show_menus(); net_udp_close(); return -1; } return(0); } int net_udp_do_join_game() { if (Netgame.game_status == NETSTAT_ENDLEVEL) { nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_NET_GAME_BETWEEN2); return 0; } if (!load_mission_by_name(Netgame.mission_name)) { nm_messagebox(NULL, 1, TXT_OK, TXT_MISSION_NOT_FOUND); return 0; } if (!net_udp_can_join_netgame(&Netgame)) { if (Netgame.numplayers == Netgame.max_numplayers) nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_GAME_FULL); else nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_IN_PROGRESS); return 0; } // Choice is valid, prepare to join in Difficulty_level = Netgame.difficulty; change_playernum_to(1); net_udp_set_game_mode(Netgame.gamemode); StartNewLevel(Netgame.levelnum); return 1; // look ma, we're in a game!!! } void net_udp_leave_game() { int nsave, i; net_udp_do_frame(1, 1); if ((multi_i_am_master())) { while (Network_sending_extras>1 && Player_joining_extras!=-1) { timer_update(); net_udp_send_extras(); } Netgame.numplayers = 0; nsave=N_players; N_players=0; for (i=1; i 0); if (UDP_Socket[1] != -1) while (udp_receive_packet( 1, packet, UPID_MAX_SIZE, &sender_addr) > 0); } void net_udp_listen() { int size; ubyte packet[UPID_MAX_SIZE]; struct _sockaddr sender_addr; if (UDP_Socket[0] != -1) { size = udp_receive_packet( 0, packet, UPID_MAX_SIZE, &sender_addr ); while ( size > 0 ) { net_udp_process_packet( packet, sender_addr, size ); size = udp_receive_packet( 0, packet, UPID_MAX_SIZE, &sender_addr ); } } if (UDP_Socket[1] != -1) { size = udp_receive_packet( 1, packet, UPID_MAX_SIZE, &sender_addr ); while ( size > 0 ) { net_udp_process_packet( packet, sender_addr, size ); size = udp_receive_packet( 1, packet, UPID_MAX_SIZE, &sender_addr ); } } #ifdef USE_TRACKER if( UDP_Socket[2] != -1 ) { size = udp_receive_packet( 2, packet, UPID_MAX_SIZE, &sender_addr ); while ( size > 0 ) { net_udp_process_packet( packet, sender_addr, size ); size = udp_receive_packet( 2, packet, UPID_MAX_SIZE, &sender_addr ); } } #endif } void net_udp_send_data(const ubyte * ptr, int len, int priority ) { char check; if (Endlevel_sequence) return; if ((UDP_MData.mbuf_size+len) > UPID_MDATA_BUF_SIZE ) { check = ptr[0]; net_udp_send_mdata(0, timer_query()); if (UDP_MData.mbuf_size != 0) Int3(); Assert(check == ptr[0]); (void)check; } Assert(UDP_MData.mbuf_size+len <= UPID_MDATA_BUF_SIZE); memcpy( &UDP_MData.mbuf[UDP_MData.mbuf_size], ptr, len ); UDP_MData.mbuf_size += len; if (priority) net_udp_send_mdata((priority==2)?1:0, timer_query()); } void net_udp_timeout_check(fix64 time) { int i = 0; static fix64 last_timeout_time = 0; if (time>=last_timeout_time+F1_0) { // Check for player timeouts for (i = 0; i < N_players; i++) { if ((i != Player_num) && (Players[i].connected != CONNECT_DISCONNECTED)) { if ((Netgame.players[i].LastPacketTime == 0) || (Netgame.players[i].LastPacketTime > time)) { Netgame.players[i].LastPacketTime = time; } else if ((time - Netgame.players[i].LastPacketTime) > UDP_TIMEOUT) { multi_disconnect_player(i); } } } last_timeout_time = time; } } void net_udp_do_frame(int force, int listen) { fix64 time = 0; static fix64 last_pdata_time = 0, last_mdata_time = 16, last_endlevel_time = 32, last_bcast_time = 48, last_resync_time = 64; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; time = timer_query(); if (WaitForRefuseAnswer && time>(RefuseTimeLimit+(F1_0*12))) WaitForRefuseAnswer=0; // Send positional update either in the regular PPS interval OR if forced AND at least every 66.6ms (nice for firing) if ((force && time >= (last_pdata_time+(F1_0/15))) || (time >= (last_pdata_time+(F1_0/Netgame.PacketsPerSec)))) { last_pdata_time = time; net_udp_send_pdata(); } if (force || (time >= (last_mdata_time+(F1_0/10)))) { last_mdata_time = time; multi_send_robot_frame(0); net_udp_send_mdata(0, time); } net_udp_noloss_process_queue(time); if (VerifyPlayerJoined!=-1 && time >= last_resync_time+F1_0) { last_resync_time = time; net_udp_resend_sync_due_to_packet_loss(); // This will resend to UDP_sync_player } if ((time>=last_endlevel_time+F1_0) && Control_center_destroyed) { last_endlevel_time = time; net_udp_send_endlevel_packet(); } // broadcast lite_info every 10 seconds if (multi_i_am_master() && time>=last_bcast_time+(F1_0*10)) { last_bcast_time = time; net_udp_broadcast_game_info(UPID_GAME_INFO_LITE); } #ifdef USE_TRACKER // If we use the tracker, tell the tracker about us every 10 seconds if( Netgame.Tracker ) { // Static variable... the last time we sent to the tracker static fix64 iLastQuery = 0; static int iAttempts = 0; fix64 iNow = timer_query(); // Set the last query to now if we must if( iLastQuery == 0 ) iLastQuery = iNow; // Test it if( iTrackerVerified == 0 && iNow >= iLastQuery + ( F1_0 * 3 ) ) { // Update it iLastQuery = iNow; iAttempts++; } // Have we had all our attempts? if( iTrackerVerified == 0 && iAttempts > 3 ) { // Turn off tracker Netgame.Tracker = 0; // Reset the static variables for next time iLastQuery = 0; iAttempts = 0; // Warn nm_messagebox( TXT_WARNING, 1, TXT_OK, "No response from tracker!\nPossible causes:\nTracker is down\nYour port is likely not open!\n\nTracker: %s\nGame port: %s", GameArg.MplTrackerAddr, UDP_MyPort ); } } #endif net_udp_ping_frame(time); if (listen) { net_udp_timeout_check(time); net_udp_listen(); if (Network_send_objects) net_udp_send_objects(); if (Network_sending_extras && VerifyPlayerJoined==-1) net_udp_send_extras(); } udp_traffic_stat(); } /* CODE FOR PACKET LOSS PREVENTION - START */ /* * Adds a packet to our queue. Should be called when an IMPORTANT mdata packet is created. * player_ack is an array which should contain 0 for each player that needs to send an ACK signal. */ void net_udp_noloss_add_queue_pkt(uint32_t pkt_num, fix64 time, ubyte *data, ushort data_size, ubyte pnum, ubyte player_ack[MAX_PLAYERS]) { int i, found = 0; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; if (!Netgame.PacketLossPrevention) return; for (i = 0; i < UDP_MDATA_STOR_QUEUE_SIZE; i++) // look for unused or oldest slot { if (UDP_mdata_queue[i].used) { if (UDP_mdata_queue[i].pkt_initial_timestamp > UDP_mdata_queue[found].pkt_initial_timestamp) found = i; } else { found = i; break; } } if (UDP_mdata_queue[found].used) // seems the slot we found is used (list is full) so screw those who still need ack's. { con_printf(CON_VERBOSE, "P#%i: MData store list is full!\n", Player_num); if (multi_i_am_master()) { for ( i=1; i= UDP_MDATA_STOR_QUEUE_SIZE) UDP_mdata_got[sender_pnum].cur_slot = 0; UDP_mdata_got[sender_pnum].pkt_num[UDP_mdata_got[sender_pnum].cur_slot] = pkt_num; return 1; } /* We got an ACK by a player. Set this player slot to positive! */ void net_udp_noloss_got_ack(ubyte *data, int data_len) { int i = 0, len = 0; uint32_t pkt_num = 0; ubyte sender_pnum = 0, dest_pnum = 0; if (data_len != 7) return; len++; sender_pnum = data[len]; len++; dest_pnum = data[len]; len++; pkt_num = GET_INTEL_INT(&data[len]); len += 4; for (i = 0; i < UDP_MDATA_STOR_QUEUE_SIZE; i++) { if ((pkt_num == UDP_mdata_queue[i].pkt_num) && (dest_pnum == UDP_mdata_queue[i].Player_num)) { con_printf(CON_VERBOSE, "P#%i: Got MData ACK for pkt_num %i from pnum %i for pnum %i\n",Player_num, pkt_num, sender_pnum, dest_pnum); UDP_mdata_queue[i].player_ack[sender_pnum] = 1; break; } } } /* Init/Free the queue. Call at start and end of a game or level. */ void net_udp_noloss_init_mdata_queue(void) { con_printf(CON_VERBOSE, "P#%i: Clearing MData store/GOT list\n",Player_num); memset(&UDP_mdata_queue,0,sizeof(UDP_mdata_store)*UDP_MDATA_STOR_QUEUE_SIZE); memset(&UDP_mdata_got,0,sizeof(UDP_mdata_recv)*MAX_PLAYERS); } /* Reset the trace list for given player when (dis)connect happens */ void net_udp_noloss_clear_mdata_got(ubyte player_num) { con_printf(CON_VERBOSE, "P#%i: Clearing GOT list for %i\n",Player_num, player_num); memset(&UDP_mdata_got[player_num].pkt_num,0,sizeof(uint32_t)*UDP_MDATA_STOR_QUEUE_SIZE); UDP_mdata_got[player_num].cur_slot = 0; } /* * The main queue-process function. * Check if we can remove a packet from queue, and check if there are packets in queue which we need to re-send */ void net_udp_noloss_process_queue(fix64 time) { int queuec = 0, plc = 0, total_len = 0; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; if (!Netgame.PacketLossPrevention) return; for (queuec = 0; queuec < UDP_MDATA_STOR_QUEUE_SIZE; queuec++) { int needack = 0; if (!UDP_mdata_queue[queuec].used) continue; // Check if at least one connected player has not ACK'd the packet for (plc = 0; plc < MAX_PLAYERS; plc++) { // If player is not playing anymore, we can remove him from list. Also remove *me* (even if that should have been done already). Also make sure Clients do not send to anyone else than Host if ((Players[plc].connected != CONNECT_PLAYING || plc == Player_num) || (!multi_i_am_master() && plc > 0)) UDP_mdata_queue[queuec].player_ack[plc] = 1; if (!UDP_mdata_queue[queuec].player_ack[plc]) { // Resend if enough time has passed. if (UDP_mdata_queue[queuec].pkt_timestamp[plc] + (F1_0/3) <= time) { ubyte buf[sizeof(UDP_mdata_info)]; int len = 0; con_printf(CON_VERBOSE, "P#%i: Resending pkt_num %i from pnum %i to pnum %i\n",Player_num, UDP_mdata_queue[queuec].pkt_num, UDP_mdata_queue[queuec].Player_num, plc); UDP_mdata_queue[queuec].pkt_timestamp[plc] = time; memset(&buf, 0, sizeof(UDP_mdata_info)); // Prepare the packet and send it buf[len] = UPID_MDATA_PNEEDACK; len++; buf[len] = UDP_mdata_queue[queuec].Player_num; len++; PUT_INTEL_INT(buf + len, UDP_mdata_queue[queuec].pkt_num); len += 4; memcpy(&buf[len], UDP_mdata_queue[queuec].data, sizeof(char)*UDP_mdata_queue[queuec].data_size); len += UDP_mdata_queue[queuec].data_size; dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[plc].protocol.udp.addr, sizeof(struct _sockaddr)); total_len += len; } needack++; } } // Check if we can remove that packet due to to it had no resend's or Timeout if (needack==0 || (UDP_mdata_queue[queuec].pkt_initial_timestamp + UDP_TIMEOUT <= time)) { if (needack) // packet timed out but still not all have ack'd. SCREW THEM NOW! { if (multi_i_am_master()) { for ( plc=1; plc= (UPID_MAX_SIZE/2)) break; } } /* CODE FOR PACKET LOSS PREVENTION - END */ void net_udp_send_mdata_direct(ubyte *data, int data_len, int pnum, int needack) { ubyte buf[sizeof(UDP_mdata_info)]; ubyte pack[MAX_PLAYERS]; int len = 0; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; if (!(data_len > 0)) return; if (!multi_i_am_master() && pnum != 0) Error("Client sent direct data to non-Host in net_udp_send_mdata_direct()!\n"); if (!Netgame.PacketLossPrevention) needack = 0; memset(&buf, 0, sizeof(UDP_mdata_info)); memset(&pack, 1, sizeof(ubyte)*MAX_PLAYERS); pack[pnum] = 0; if (needack) buf[len] = UPID_MDATA_PNEEDACK; else buf[len] = UPID_MDATA_PNORM; len++; buf[len] = Player_num; len++; if (needack) { UDP_MData.pkt_num++; Assert(UDP_MDATA_STOR_QUEUE_SIZE*100 < INT_MAX); if (UDP_MData.pkt_num > UDP_MDATA_STOR_QUEUE_SIZE*100) // roll over at some point UDP_MData.pkt_num = 0; PUT_INTEL_INT(buf + len, UDP_MData.pkt_num); len += 4; } memcpy(&buf[len], data, sizeof(char)*data_len); len += data_len; dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[pnum].protocol.udp.addr, sizeof(struct _sockaddr)); if (needack) net_udp_noloss_add_queue_pkt(UDP_MData.pkt_num, timer_query(), data, data_len, Player_num, pack); } void net_udp_send_mdata(int needack, fix64 time) { ubyte buf[sizeof(UDP_mdata_info)]; ubyte pack[MAX_PLAYERS]; int len = 0, i = 0; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; if (!(UDP_MData.mbuf_size > 0)) return; if (!Netgame.PacketLossPrevention) needack = 0; memset(&buf, 0, sizeof(UDP_mdata_info)); memset(&pack, 1, sizeof(ubyte)*MAX_PLAYERS); if (needack) buf[len] = UPID_MDATA_PNEEDACK; else buf[len] = UPID_MDATA_PNORM; len++; buf[len] = Player_num; len++; if (needack) { UDP_MData.pkt_num++; PUT_INTEL_INT(buf + len, UDP_MData.pkt_num); len += 4; } memcpy(&buf[len], UDP_MData.mbuf, sizeof(char)*UDP_MData.mbuf_size); len += UDP_MData.mbuf_size; if (multi_i_am_master()) { for (i = 1; i < MAX_PLAYERS; i++) { if (Players[i].connected == CONNECT_PLAYING) { dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)); pack[i] = 0; } } } else { dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[0].protocol.udp.addr, sizeof(struct _sockaddr)); pack[0] = 0; } if (needack) net_udp_noloss_add_queue_pkt(UDP_MData.pkt_num, time, UDP_MData.mbuf, UDP_MData.mbuf_size, Player_num, pack); // Clear UDP_MData except pkt_num. That one must not be deleted so we can clearly keep track of important packets. UDP_MData.type = 0; UDP_MData.Player_num = 0; UDP_MData.mbuf_size = 0; memset(&UDP_MData.mbuf, 0, sizeof(ubyte)*UPID_MDATA_BUF_SIZE); } void net_udp_process_mdata (ubyte *data, int data_len, struct _sockaddr sender_addr, int needack) { int pnum = data[1], dataoffset = (needack?6:2); // Check if packet might be bogus if ((pnum < 0) || (data_len > sizeof(UDP_mdata_info))) return; // Check if it came from valid IP if (multi_i_am_master()) { if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[pnum].protocol.udp.addr, sizeof(struct _sockaddr))) { return; } } else { if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, sizeof(struct _sockaddr))) { return; } } // Add needack packet and check for possible redundancy if (needack) { if (!net_udp_noloss_validate_mdata(GET_INTEL_SHORT(&data[2]), pnum, sender_addr)) return; } // send this to everyone else (if master) if (multi_i_am_master()) { ubyte pack[MAX_PLAYERS]; int i = 0; memset(&pack, 1, sizeof(ubyte)*MAX_PLAYERS); for (i = 1; i < MAX_PLAYERS; i++) { if ((i != pnum) && Players[i].connected == CONNECT_PLAYING) { dxx_sendto (UDP_Socket[0], data, data_len, 0, (struct sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)); pack[i] = 0; } } if (needack && N_players > 2) { net_udp_noloss_add_queue_pkt(GET_INTEL_SHORT(&data[2]), timer_query(), data+dataoffset, data_len-dataoffset, pnum, pack); } } // Check if we are in correct state to process the packet if (!((Network_status == NETSTAT_PLAYING)||(Network_status == NETSTAT_ENDLEVEL) || Network_status==NETSTAT_WAITING)) return; // Process if (Endlevel_sequence || (Network_status == NETSTAT_ENDLEVEL)) { int old_Endlevel_sequence = Endlevel_sequence; Endlevel_sequence = 1; multi_process_bigdata(data+dataoffset, data_len-dataoffset); Endlevel_sequence = old_Endlevel_sequence; return; } multi_process_bigdata( data+dataoffset, data_len-dataoffset ); } void net_udp_send_pdata() { ubyte buf[sizeof(UDP_frame_info)]; int len = 0, i = 0; if (!(Game_mode&GM_NETWORK) || UDP_Socket[0] == -1) return; if (Players[Player_num].connected != CONNECT_PLAYING) return; memset(&buf, 0, sizeof(UDP_frame_info)); buf[len] = UPID_PDATA; len++; buf[len] = Player_num; len++; buf[len] = Players[Player_num].connected; len++; // 3 if (Netgame.ShortPackets) { shortpos spp; memset(&spp, 0, sizeof(shortpos)); create_shortpos(&spp, Objects+Players[Player_num].objnum, 0); memcpy(buf + len, &spp.bytemat, 9); len += 9; PUT_INTEL_SHORT(buf+len, spp.xo); len += 2; PUT_INTEL_SHORT(buf+len, spp.yo); len += 2; PUT_INTEL_SHORT(buf+len, spp.zo); len += 2; PUT_INTEL_SHORT(buf+len, spp.segment); len += 2; PUT_INTEL_SHORT(buf+len, spp.velx); len += 2; PUT_INTEL_SHORT(buf+len, spp.vely); len += 2; PUT_INTEL_SHORT(buf+len, spp.velz); len += 2; // 23 + 3 = 26 } else { quaternionpos qpp; memset(&qpp, 0, sizeof(quaternionpos)); create_quaternionpos(&qpp, Objects+Players[Player_num].objnum, 0); PUT_INTEL_SHORT(buf+len, qpp.orient.w); len += 2; PUT_INTEL_SHORT(buf+len, qpp.orient.x); len += 2; PUT_INTEL_SHORT(buf+len, qpp.orient.y); len += 2; PUT_INTEL_SHORT(buf+len, qpp.orient.z); len += 2; PUT_INTEL_INT(buf+len, qpp.pos.x); len += 4; PUT_INTEL_INT(buf+len, qpp.pos.y); len += 4; PUT_INTEL_INT(buf+len, qpp.pos.z); len += 4; PUT_INTEL_INT(buf+len, qpp.vel.x); len += 4; PUT_INTEL_INT(buf+len, qpp.vel.y); len += 4; PUT_INTEL_INT(buf+len, qpp.vel.z); len += 4; PUT_INTEL_INT(buf+len, qpp.rotvel.x); len += 4; PUT_INTEL_INT(buf+len, qpp.rotvel.y); len += 4; PUT_INTEL_INT(buf+len, qpp.rotvel.z); len += 4; // 44 + 3 = 47 } if (multi_i_am_master()) { for (i = 1; i < MAX_PLAYERS; i++) if (Players[i].connected != CONNECT_DISCONNECTED) dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)); } else { dxx_sendto (UDP_Socket[0], buf, len, 0, (struct sockaddr *)&Netgame.players[0].protocol.udp.addr, sizeof(struct _sockaddr)); } } void net_udp_process_pdata ( ubyte *data, int data_len, struct _sockaddr sender_addr ) { UDP_frame_info pd; int len = 0, i = 0; if ( !( Game_mode & GM_NETWORK && ( Network_status == NETSTAT_PLAYING || Network_status == NETSTAT_ENDLEVEL || Network_status==NETSTAT_WAITING ) ) ) return; len++; memset(&pd, 0, sizeof(UDP_frame_info)); if (data_len > sizeof(UDP_frame_info)) return; if ((Netgame.ShortPackets && data_len != UPID_PDATA_S_SIZE) || (!Netgame.ShortPackets && data_len != UPID_PDATA_Q_SIZE)) return; if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[((multi_i_am_master())?(data[len]):(0))].protocol.udp.addr, sizeof(struct _sockaddr))) return; pd.Player_num = data[len]; len++; pd.connected = data[len]; len++; if (Netgame.ShortPackets) { memcpy(&pd.ptype.spp.bytemat, &(data[len]), 9); len += 9; pd.ptype.spp.xo = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.yo = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.zo = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.segment = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.velx = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.vely = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.spp.velz = GET_INTEL_SHORT(&data[len]); len += 2; } else { pd.ptype.qpp.orient.w = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.qpp.orient.x = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.qpp.orient.y = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.qpp.orient.z = GET_INTEL_SHORT(&data[len]); len += 2; pd.ptype.qpp.pos.x = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.pos.y = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.pos.z = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.vel.x = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.vel.y = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.vel.z = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.rotvel.x = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.rotvel.y = GET_INTEL_INT(&data[len]); len += 4; pd.ptype.qpp.rotvel.z = GET_INTEL_INT(&data[len]); len += 4; } if (multi_i_am_master()) // I am host - must relay this packet to others! { if (pd.Player_num > 0 && pd.Player_num <= N_players && Players[pd.Player_num].connected == CONNECT_PLAYING) // some checking wether this packet is legal { for (i = 1; i < MAX_PLAYERS; i++) { if (i != pd.Player_num && Players[i].connected != CONNECT_DISCONNECTED) // not to sender or disconnected players - right. dxx_sendto (UDP_Socket[0], data, data_len, 0, (struct sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)); } } } net_udp_read_pdata_packet (&pd); } void net_udp_read_pdata_packet(UDP_frame_info *pd) { int TheirPlayernum; int TheirObjnum; object * TheirObj = NULL; TheirPlayernum = pd->Player_num; TheirObjnum = Players[pd->Player_num].objnum; if (multi_i_am_master()) { // latecoming player seems to successfully have synced if ( VerifyPlayerJoined != -1 && TheirPlayernum == VerifyPlayerJoined ) VerifyPlayerJoined=-1; // we say that guy is disconnected so we do not want him/her in game if ( Players[TheirPlayernum].connected == CONNECT_DISCONNECTED ) return; } else { // only by reading pdata a client can know if a player reconnected. So do that here. // NOTE: we might do this somewhere else - maybe with a sync packet like when adding a fresh player. if ( Players[TheirPlayernum].connected == CONNECT_DISCONNECTED && pd->connected == CONNECT_PLAYING ) { Players[TheirPlayernum].connected = CONNECT_PLAYING; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_reconnect(TheirPlayernum); digi_play_sample( SOUND_HUD_MESSAGE, F1_0); ClipRank (&Netgame.players[TheirPlayernum].rank); if (PlayerCfg.NoRankings) HUD_init_message(HM_MULTI, "'%s' %s", Players[TheirPlayernum].callsign, TXT_REJOIN ); else HUD_init_message(HM_MULTI, "%s'%s' %s", RankStrings[Netgame.players[TheirPlayernum].rank],Players[TheirPlayernum].callsign, TXT_REJOIN ); multi_send_score(); net_udp_noloss_clear_mdata_got(TheirPlayernum); } } if (Players[TheirPlayernum].connected != CONNECT_PLAYING || TheirPlayernum == Player_num) return; if (!multi_quit_game && (TheirPlayernum >= N_players)) { if (Network_status!=NETSTAT_WAITING) { Int3(); // We missed an important packet! multi_consistency_error(0); return; } else return; } TheirObj = &Objects[TheirObjnum]; Netgame.players[TheirPlayernum].LastPacketTime = timer_query(); //------------ Read the player's ship's object info ---------------------- if (Netgame.ShortPackets) extract_shortpos(TheirObj, &pd->ptype.spp, 0); else extract_quaternionpos(TheirObj, &pd->ptype.qpp, 0); if (TheirObj->movement_type == MT_PHYSICS) set_thrust_from_velocity(TheirObj); } // Send the ping list in regular intervals void net_udp_ping_frame(fix64 time) { static fix64 PingTime = 0; if ((PingTime + F1_0) < time) { ubyte buf[UPID_PING_SIZE]; int len = 0, i = 0; memset(&buf, 0, sizeof(ubyte)*UPID_PING_SIZE); buf[len] = UPID_PING; len++; memcpy(&buf[len], &time, 8); len += 8; for (i = 1; i < MAX_PLAYERS; i++) { PUT_INTEL_INT(buf + len, Netgame.players[i].ping); len += 4; } for (i = 1; i < MAX_PLAYERS; i++) { if (Players[i].connected == CONNECT_DISCONNECTED) continue; dxx_sendto (UDP_Socket[0], buf, sizeof(buf), 0, (struct sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr)); } PingTime = time; } } // Got a PING from host. Apply the pings to our players and respond to host. void net_udp_process_ping(ubyte *data, int data_len, struct _sockaddr sender_addr) { fix64 host_ping_time = 0; ubyte buf[UPID_PONG_SIZE]; int i, len = 0; // if (memcmp((struct _sockaddr *)&Netgame.players[0].protocol.udp.addr, (struct _sockaddr *)&sender_addr, sizeof(struct _sockaddr))) return; len++; // Skip UPID byte; memcpy(&host_ping_time, &data[len], 8); len += 8; for (i = 1; i < MAX_PLAYERS; i++) { Netgame.players[i].ping = GET_INTEL_INT(&(data[len])); len += 4; } buf[0] = UPID_PONG; buf[1] = Player_num; memcpy(&buf[2], &host_ping_time, 8); dxx_sendto (UDP_Socket[0], buf, sizeof(buf), 0, (struct sockaddr *)&sender_addr, sizeof(struct _sockaddr)); } // Got a PONG from a client. Check the time and add it to our players. void net_udp_process_pong(ubyte *data, int data_len, struct _sockaddr sender_addr) { fix64 client_pong_time = 0; int i = 0; if (memcmp((struct _sockaddr *)&sender_addr, (struct _sockaddr *)&Netgame.players[data[1]].protocol.udp.addr, sizeof(struct _sockaddr))) return; if (data[1] >= MAX_PLAYERS || data[1] < 1) return; if (i == MAX_PLAYERS) return; memcpy(&client_pong_time, &data[2], 8); Netgame.players[data[1]].ping = f2i(fixmul(timer_query() - client_pong_time,i2f(1000))); if (Netgame.players[data[1]].ping < 0) Netgame.players[data[1]].ping = 0; if (Netgame.players[data[1]].ping > 9999) Netgame.players[data[1]].ping = 9999; } void net_udp_do_refuse_stuff (UDP_sequence_packet *their) { int i,new_player_num; ClipRank (&their->player.rank); for (i=0;iplayer.callsign )) && !memcmp((struct _sockaddr *)&their->player.protocol.udp.addr, (struct _sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr))) { net_udp_welcome_player(their); return; } } if (!WaitForRefuseAnswer) { for (i=0;iplayer.callsign )) && !memcmp((struct _sockaddr *)&their->player.protocol.udp.addr, (struct _sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr))) { net_udp_welcome_player(their); return; } } digi_play_sample (SOUND_CONTROL_CENTER_WARNING_SIREN,F1_0*2); if (Game_mode & GM_TEAM) { if (!PlayerCfg.NoRankings) { HUD_init_message(HM_MULTI, "%s %s wants to join",RankStrings[their->player.rank],their->player.callsign); } else { HUD_init_message(HM_MULTI, "%s wants to join",their->player.callsign); } HUD_init_message(HM_MULTI, "Alt-1 assigns to team %s. Alt-2 to team %s",Netgame.team_name[0],Netgame.team_name[1]); } else { HUD_init_message(HM_MULTI, "%s wants to join (accept: F6)",their->player.callsign); } strcpy (RefusePlayerName,their->player.callsign); RefuseTimeLimit=timer_query(); RefuseThisPlayer=0; WaitForRefuseAnswer=1; } else { for (i=0;iplayer.callsign )) && !memcmp((struct _sockaddr *)&their->player.protocol.udp.addr, (struct _sockaddr *)&Netgame.players[i].protocol.udp.addr, sizeof(struct _sockaddr))) { net_udp_welcome_player(their); return; } } if (strcmp(their->player.callsign,RefusePlayerName)) return; if (RefuseThisPlayer) { RefuseTimeLimit=0; RefuseThisPlayer=0; WaitForRefuseAnswer=0; if (Game_mode & GM_TEAM) { new_player_num=net_udp_get_new_player_num (their); Assert (RefuseTeam==1 || RefuseTeam==2); if (RefuseTeam==1) Netgame.team_vector &=(~(1< RefuseTimeLimit+REFUSE_INTERVAL) { RefuseTimeLimit=0; RefuseThisPlayer=0; WaitForRefuseAnswer=0; if (!strcmp (their->player.callsign,RefusePlayerName)) { net_udp_dump_player(their->player.protocol.udp.addr, DUMP_DORK); } return; } } } int net_udp_get_new_player_num (UDP_sequence_packet *their) { int i; their=their; if ( N_players < Netgame.max_numplayers) return (N_players); else { // Slots are full but game is open, see if anyone is // disconnected and replace the oldest player with this new one int oldest_player = -1; fix64 oldest_time = timer_query(); Assert(N_players == Netgame.max_numplayers); for (i = 0; i < N_players; i++) { if ( (!Players[i].connected) && (Netgame.players[i].LastPacketTime < oldest_time)) { oldest_time = Netgame.players[i].LastPacketTime; oldest_player = i; } } return (oldest_player); } } void net_udp_send_extras () { static fix64 last_send_time = 0; if (last_send_time + (F1_0/50) > timer_query()) return; last_send_time = timer_query(); Assert (Player_joining_extras>-1); if (Network_sending_extras==3 && (Netgame.PlayTimeAllowed || Netgame.KillGoal)) multi_send_kill_goal_counts(); if (Network_sending_extras==2) multi_send_powcap_update(); if (Network_sending_extras==1 && Game_mode & GM_BOUNTY) multi_send_bounty(); Network_sending_extras--; if (!Network_sending_extras) Player_joining_extras=-1; } static int show_game_rules_handler(window *wind, d_event *event, netgame_info *netgame) { int k; int w = FSPACX(280), h = FSPACY(130); switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); break; case EVENT_KEY_COMMAND: k = event_key_get(event); switch (k) { case KEY_ENTER: case KEY_SPACEBAR: case KEY_ESC: window_close(wind); return 1; } break; case EVENT_WINDOW_DRAW: timer_delay2(50); gr_set_current_canvas(NULL); nm_draw_background(((SWIDTH-w)/2)-BORDERX,((SHEIGHT-h)/2)-BORDERY,((SWIDTH-w)/2)+w+BORDERX,((SHEIGHT-h)/2)+h+BORDERY); gr_set_current_canvas(window_get_canvas(wind)); grd_curcanv->cv_font = MEDIUM3_FONT; gr_set_fontcolor(gr_find_closest_color_current(29,29,47),-1); gr_string( 0x8000, FSPACY(35), "NETGAME INFO" ); grd_curcanv->cv_font = GAME_FONT; gr_printf( FSPACX( 25),FSPACY( 55), "Reactor Life:"); gr_printf( FSPACX( 25),FSPACY( 61), "Max Time:"); gr_printf( FSPACX( 25),FSPACY( 67), "Kill Goal:"); gr_printf( FSPACX( 25),FSPACY( 73), "Packets per sec.:"); gr_printf( FSPACX(155),FSPACY( 55), "Invul when reappearing:"); gr_printf( FSPACX(155),FSPACY( 61), "Bright player ships:"); gr_printf( FSPACX(155),FSPACY( 67), "Show enemy names on hud:"); gr_printf( FSPACX(155),FSPACY( 73), "Show players on automap:"); gr_printf( FSPACX(155),FSPACY( 79), "No friendly Fire:"); gr_printf( FSPACX( 25),FSPACY(100), "Allowed Objects"); gr_printf( FSPACX( 25),FSPACY(110), "Laser Upgrade:"); gr_printf( FSPACX( 25),FSPACY(116), "Quad Laser:"); gr_printf( FSPACX( 25),FSPACY(122), "Vulcan Cannon:"); gr_printf( FSPACX( 25),FSPACY(128), "Spreadfire Cannon:"); gr_printf( FSPACX( 25),FSPACY(134), "Plasma Cannon:"); gr_printf( FSPACX( 25),FSPACY(140), "Fusion Cannon:"); gr_printf( FSPACX(170),FSPACY(110), "Homing Missile:"); gr_printf( FSPACX(170),FSPACY(116), "Proximity Bomb:"); gr_printf( FSPACX(170),FSPACY(122), "Smart Missile:"); gr_printf( FSPACX(170),FSPACY(128), "Mega Missile:"); gr_printf( FSPACX( 25),FSPACY(150), "Invulnerability:"); gr_printf( FSPACX( 25),FSPACY(156), "Cloak:"); gr_set_fontcolor(gr_find_closest_color_current(255,255,255),-1); gr_printf( FSPACX(115),FSPACY( 55), "%i Min", netgame->control_invul_time/F1_0/60); gr_printf( FSPACX(115),FSPACY( 61), "%i Min", netgame->PlayTimeAllowed*5); gr_printf( FSPACX(115),FSPACY( 67), "%i", netgame->KillGoal*5); gr_printf( FSPACX(115),FSPACY( 73), "%i", netgame->PacketsPerSec); gr_printf( FSPACX(275),FSPACY( 55), netgame->InvulAppear?"ON":"OFF"); gr_printf( FSPACX(275),FSPACY( 61), netgame->BrightPlayers?"ON":"OFF"); gr_printf( FSPACX(275),FSPACY( 67), netgame->ShowEnemyNames?"ON":"OFF"); gr_printf( FSPACX(275),FSPACY( 73), netgame->game_flags&NETGAME_FLAG_SHOW_MAP?"ON":"OFF"); gr_printf( FSPACX(275),FSPACY( 79), netgame->NoFriendlyFire?"ON":"OFF"); gr_printf( FSPACX(130),FSPACY(110), netgame->AllowedItems&NETFLAG_DOLASER?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(116), netgame->AllowedItems&NETFLAG_DOQUAD?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(122), netgame->AllowedItems&NETFLAG_DOVULCAN?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(128), netgame->AllowedItems&NETFLAG_DOSPREAD?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(134), netgame->AllowedItems&NETFLAG_DOPLASMA?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(140), netgame->AllowedItems&NETFLAG_DOFUSION?"YES":"NO"); gr_printf( FSPACX(275),FSPACY(110), netgame->AllowedItems&NETFLAG_DOHOMING?"YES":"NO"); gr_printf( FSPACX(275),FSPACY(116), netgame->AllowedItems&NETFLAG_DOPROXIM?"YES":"NO"); gr_printf( FSPACX(275),FSPACY(122), netgame->AllowedItems&NETFLAG_DOSMART?"YES":"NO"); gr_printf( FSPACX(275),FSPACY(128), netgame->AllowedItems&NETFLAG_DOMEGA?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(150), netgame->AllowedItems&NETFLAG_DOINVUL?"YES":"NO"); gr_printf( FSPACX(130),FSPACY(156), netgame->AllowedItems&NETFLAG_DOCLOAK?"YES":"NO"); gr_set_current_canvas(NULL); break; default: break; } return 0; } void net_udp_show_game_rules(netgame_info *netgame) { gr_set_current_canvas(NULL); window_create(&grd_curscreen->sc_canvas, (SWIDTH - FSPACX(320))/2, (SHEIGHT - FSPACY(200))/2, FSPACX(320), FSPACY(200), (int (*)(window *, d_event *, void *))show_game_rules_handler, netgame); } static int show_game_info_handler(newmenu *menu, d_event *event, netgame_info *netgame) { if (event->type != EVENT_NEWMENU_SELECTED) return 0; if (newmenu_get_citem(menu) != 1) return 0; net_udp_show_game_rules(netgame); return 1; } int net_udp_show_game_info() { char rinfo[512],*info=rinfo; int c; netgame_info *netgame = &Netgame; memset(info,0,sizeof(char)*256); info+=sprintf(info,"\nConnected to\n\"%s\"\n",netgame->game_name); if(!netgame->mission_title) info+=sprintf(info,"Descent: First Strike"); else info+=sprintf(info,"%s",netgame->mission_title); if( netgame->levelnum >= 0 ) { info+=sprintf (info," - Lvl %i",netgame->levelnum); } else { info+=sprintf (info," - Lvl S%i",(netgame->levelnum*-1)); } info+=sprintf (info,"\n\nDifficulty: %s",MENU_DIFFICULTY_TEXT(netgame->difficulty)); unsigned gamemode = netgame->gamemode; info+=sprintf (info,"\nGame Mode: %s",gamemode < (sizeof(GMNames) / sizeof(GMNames[0])) ? GMNames[gamemode] : "INVALID"); info+=sprintf (info,"\nPlayers: %i/%i",netgame->numplayers,netgame->max_numplayers); c=nm_messagebox1("WELCOME", (int (*)(newmenu *, d_event *, void *))show_game_info_handler, netgame, 2, "JOIN GAME", "GAME INFO", rinfo); if (c==0) return 1; //else if (c==1) // handled in above callback else return 0; } #endif dxx-rebirth-0.58.1-d1x/main/net_udp.h000066400000000000000000000147321217717257200173140ustar00rootroot00000000000000/* * * Prototypes for UDP-protocol network management functions. * */ #include "multi.h" // Exported functions int net_udp_setup_game(void); void net_udp_manual_join_game(); void net_udp_list_join_game(); int net_udp_objnum_is_past(int objnum); void net_udp_do_frame(int force, int listen); void net_udp_send_data(const ubyte * ptr, int len, int priority ); void net_udp_leave_game(); int net_udp_endlevel(int *secret); int net_udp_kmatrix_poll1( newmenu *menu, d_event *event, void *userdata ); int net_udp_kmatrix_poll2( newmenu *menu, d_event *event, void *userdata ); void net_udp_send_endlevel_packet(); void net_udp_dump_player(struct _sockaddr dump_addr, int why); void net_udp_disconnect_player(int playernum); int net_udp_level_sync(); void net_udp_send_mdata_direct(ubyte *data, int data_len, int pnum, int priority); // Some defines #ifdef IPv6 #define UDP_MCASTv6_ADDR "ff02::1" #endif #define UDP_BCAST_ADDR "255.255.255.255" #define UDP_PORT_DEFAULT 42424 // Our default port - easy to remember: D = 4, X = 24, X = 24 #define UDP_MANUAL_ADDR_DEFAULT "localhost" #ifdef USE_TRACKER #define TRACKER_ADDR_DEFAULT "dxxtracker.reenigne.net" #define TRACKER_PORT_DEFAULT 42420 #endif #define UDP_REQ_ID "D1XR" // ID string for a request packet #define UDP_MAX_NETGAMES 900 #define UDP_NETGAMES_PPAGE 12 // Netgames on one page of Netlist #define UDP_NETGAMES_PAGES 75 // Pages available on Netlist (UDP_MAX_NETGAMES/UDP_NETGAMES_PPAGE) #define UDP_TIMEOUT (5*F1_0) // 5 seconds disconnect timeout #define UDP_MDATA_STOR_QUEUE_SIZE 500 // Store up to 500 MDATA packets // UDP-Packet identificators (ubyte) and their (max. sizes). #define UPID_VERSION_DENY 1 // Netgame join or info has been denied due to version difference. #define UPID_VERSION_DENY_SIZE 9 #define UPID_GAME_INFO_REQ 2 // Requesting all info about a netgame. #define UPID_GAME_INFO_REQ_SIZE 13 #define UPID_GAME_INFO_LITE_REQ_SIZE 11 #define UPID_GAME_INFO 3 // Packet containing all info about a netgame. #define UPID_GAME_INFO_SIZE (360 + (NETGAME_NAME_LEN+1) + (MISSION_NAME_LEN+1) + ((MAX_PLAYERS+4)*(CALLSIGN_LEN+1))) #define UPID_GAME_INFO_LITE_REQ 4 // Requesting lite info about a netgame. Used for discovering games. #define UPID_GAME_INFO_LITE 5 // Packet containing lite netgame info. #define UPID_GAME_INFO_LITE_SIZE (31 + (NETGAME_NAME_LEN+1) + (MISSION_NAME_LEN+1)) #define UPID_DUMP 6 // Packet containing why player cannot join this game. #define UPID_DUMP_SIZE 2 #define UPID_ADDPLAYER 7 // Packet from Host containing info about a new player. #define UPID_REQUEST 8 // New player says: "I want to be inside of you!" (haha, sorry I could not resist) / Packet containing request to join the game actually. #define UPID_QUIT_JOINING 9 // Packet from a player who suddenly quits joining. #define UPID_SEQUENCE_SIZE (3 + (CALLSIGN_LEN+1)) #define UPID_SYNC 10 // Packet from host containing full netgame info to sync players up. #define UPID_OBJECT_DATA 11 // Packet from host containing object buffer. #define UPID_PING 12 // Packet from host containing his GameTime and the Ping list. Client returns this time to host as UPID_PONG and adapts the ping list. #define UPID_PING_SIZE 37 #define UPID_PONG 13 // Packet answer from client to UPID_PING. Contains the time the initial ping packet was sent. #define UPID_PONG_SIZE 10 #define UPID_ENDLEVEL_H 14 // Packet from Host to all Clients containing connect-states and kills information about everyone in the game. #define UPID_ENDLEVEL_C 15 // Packet from Client to Host containing connect-state and kills information from this Client. #define UPID_PDATA 16 // Packet from player containing his movement data. #define UPID_PDATA_S_SIZE 26 #define UPID_PDATA_Q_SIZE 47 #define UPID_MDATA_PNORM 17 // Packet containing multi buffer from a player. Priority 0,1 - no ACK needed. #define UPID_MDATA_PNEEDACK 18 // Packet containing multi buffer from a player. Priority 2 - ACK needed. Also contains pkt_num #define UPID_MDATA_ACK 19 // ACK packet for UPID_MDATA_P1. #define UPID_MAX_SIZE 1024 // Max size for a packet #define UPID_MDATA_BUF_SIZE 454 #ifdef USE_TRACKER # define UPID_TRACKER_VERIFY 21 // The tracker has successfully gotten a hold of us # define UPID_TRACKER_INCGAME 22 // The tracker is sending us some game info #endif // Structure keeping lite game infos (for netlist, etc.) typedef struct UDP_netgame_info_lite { struct _sockaddr game_addr; short program_iver[3]; fix GameID; char game_name[NETGAME_NAME_LEN+1]; char mission_title[MISSION_NAME_LEN+1]; char mission_name[9]; int32_t levelnum; ubyte gamemode; ubyte RefusePlayers; ubyte difficulty; ubyte game_status; ubyte numconnected; ubyte max_numplayers; ubyte game_flags; } __pack__ UDP_netgame_info_lite; typedef struct UDP_sequence_packet { ubyte type; netplayer_info player; } __pack__ UDP_sequence_packet; // player position packet structure typedef struct UDP_frame_info { ubyte type; ubyte Player_num; ubyte connected; union { quaternionpos qpp; shortpos spp; } __pack__ ptype; } __pack__ UDP_frame_info; // packet structure for multi-buffer typedef struct UDP_mdata_info { ubyte type; ubyte Player_num; uint32_t pkt_num; ushort mbuf_size; ubyte mbuf[UPID_MDATA_BUF_SIZE]; } __pack__ UDP_mdata_info; // structure to store MDATA to maybe resend typedef struct UDP_mdata_store { int used; fix64 pkt_initial_timestamp; // initial timestamp to see if packet is outdated fix64 pkt_timestamp[MAX_PLAYERS]; // Packet timestamp int pkt_num; // Packet number ubyte Player_num; // sender of this packet ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected ubyte data[UPID_MDATA_BUF_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose ushort data_size; } __pack__ UDP_mdata_store; // structure to keep track of MDATA packets we've already got typedef struct UDP_mdata_recv { int pkt_num[UDP_MDATA_STOR_QUEUE_SIZE]; int cur_slot; // index we can use for a new pkt_num } __pack__ UDP_mdata_recv; dxx-rebirth-0.58.1-d1x/main/newdemo.c000066400000000000000000002710701217717257200173070ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code to make a complete demo playback system. * */ #include #include #include #include // for memset #include #include #include "u_mem.h" #include "inferno.h" #include "game.h" #include "gr.h" #include "stdlib.h" #include "bm.h" #include "3d.h" #include "segment.h" #include "texmap.h" #include "laser.h" #include "key.h" #include "gameseg.h" #include "object.h" #include "physics.h" #include "slew.h" #include "render.h" #include "wall.h" #include "vclip.h" #include "polyobj.h" #include "fireball.h" #include "laser.h" #include "dxxerror.h" #include "ai.h" #include "hostage.h" #include "morph.h" #include "powerup.h" #include "fuelcen.h" #include "sounds.h" #include "collide.h" #include "lighting.h" #include "newdemo.h" #include "gameseq.h" #include "gamesave.h" #include "gamemine.h" #include "switch.h" #include "gauges.h" #include "player.h" #include "vecmat.h" #include "menu.h" #include "args.h" #include "palette.h" #include "multi.h" #include "text.h" #include "cntrlcen.h" #include "aistruct.h" #include "mission.h" #include "piggy.h" #include "byteswap.h" #include "physfsx.h" #include "console.h" #include "playsave.h" #ifdef EDITOR #include "editor/editor.h" #endif #define ND_EVENT_EOF 0 // EOF #define ND_EVENT_START_DEMO 1 // Followed by 16 character, NULL terminated filename of .SAV file to use #define ND_EVENT_START_FRAME 2 // Followed by integer frame number, then a fix FrameTime #define ND_EVENT_VIEWER_OBJECT 3 // Followed by an object structure #define ND_EVENT_RENDER_OBJECT 4 // Followed by an object structure #define ND_EVENT_SOUND 5 // Followed by int soundum #define ND_EVENT_SOUND_ONCE 6 // Followed by int soundum #define ND_EVENT_SOUND_3D 7 // Followed by int soundum, int angle, int volume #define ND_EVENT_WALL_HIT_PROCESS 8 // Followed by int segnum, int side, fix damage #define ND_EVENT_TRIGGER 9 // Followed by int segnum, int side, int objnum #define ND_EVENT_HOSTAGE_RESCUED 10 // Followed by int hostage_type #define ND_EVENT_SOUND_3D_ONCE 11 // Followed by int soundum, int angle, int volume #define ND_EVENT_MORPH_FRAME 12 // Followed by ? data #define ND_EVENT_WALL_TOGGLE 13 // Followed by int seg, int side #define ND_EVENT_HUD_MESSAGE 14 // Followed by char size, char * string (+null) #define ND_EVENT_CONTROL_CENTER_DESTROYED 15 // Just a simple flag #define ND_EVENT_PALETTE_EFFECT 16 // Followed by short r,g,b #define ND_EVENT_PLAYER_ENERGY 17 // followed by byte energy #define ND_EVENT_PLAYER_SHIELD 18 // followed by byte shields #define ND_EVENT_PLAYER_FLAGS 19 // followed by player flags #define ND_EVENT_PLAYER_WEAPON 20 // followed by weapon type and weapon number #define ND_EVENT_EFFECT_BLOWUP 21 // followed by segment, side, and pnt #define ND_EVENT_HOMING_DISTANCE 22 // followed by homing distance #define ND_EVENT_LETTERBOX 23 // letterbox mode for death seq. #define ND_EVENT_RESTORE_COCKPIT 24 // restore cockpit after death #define ND_EVENT_REARVIEW 25 // going to rear view mode #define ND_EVENT_WALL_SET_TMAP_NUM1 26 // Wall changed #define ND_EVENT_WALL_SET_TMAP_NUM2 27 // Wall changed #define ND_EVENT_NEW_LEVEL 28 // followed by level number #define ND_EVENT_MULTI_CLOAK 29 // followed by player num #define ND_EVENT_MULTI_DECLOAK 30 // followed by player num #define ND_EVENT_RESTORE_REARVIEW 31 // restore cockpit after rearview mode #define ND_EVENT_MULTI_DEATH 32 // with player number #define ND_EVENT_MULTI_KILL 33 // with player number #define ND_EVENT_MULTI_CONNECT 34 // with player number #define ND_EVENT_MULTI_RECONNECT 35 // with player number #define ND_EVENT_MULTI_DISCONNECT 36 // with player number #define ND_EVENT_MULTI_SCORE 37 // playernum / score #define ND_EVENT_PLAYER_SCORE 38 // followed by score #define ND_EVENT_PRIMARY_AMMO 39 // with old/new ammo count #define ND_EVENT_SECONDARY_AMMO 40 // with old/new ammo count #define ND_EVENT_DOOR_OPENING 41 // with segment/side #define ND_EVENT_LASER_LEVEL 42 // with old/new level #define ND_EVENT_LINK_SOUND_TO_OBJ 43 // record digi_link_sound_to_object3 #define ND_EVENT_KILL_SOUND_TO_OBJ 44 // record digi_kill_sound_linked_to_object #define NORMAL_PLAYBACK 0 #define SKIP_PLAYBACK 1 #define INTERPOLATE_PLAYBACK 2 #define INTERPOL_FACTOR (F1_0 + (F1_0/5)) #define DEMO_VERSION_SHAREWARE 5 #define DEMO_VERSION 13 #define DEMO_FILENAME DEMO_DIR "tmpdemo.dem" #define DEMO_MAX_LEVELS 29 #define DEMO_GAME_TYPE_SHAREWARE 1 #define DEMO_GAME_TYPE 2 // In- and Out-files PHYSFS_file *infile; PHYSFS_file *outfile = NULL; // Some globals int Newdemo_state = 0; int Newdemo_game_mode = 0; int Newdemo_vcr_state = 0; int Newdemo_show_percentage=1; sbyte Newdemo_do_interpolate = 1; int Newdemo_num_written; // local var used for swapping endian demos static int swap_endian = 0; // playback variables static unsigned int nd_playback_v_demosize; static char nd_playback_v_save_callsign[CALLSIGN_LEN+1]; static sbyte nd_playback_v_at_eof; static sbyte nd_playback_v_cntrlcen_destroyed = 0; static sbyte nd_playback_v_bad_read; static int nd_playback_v_framecount; static fix nd_playback_total, nd_recorded_total, nd_recorded_time; static sbyte nd_playback_v_style; static ubyte nd_playback_v_dead = 0, nd_playback_v_rear = 0; // record variables #define REC_DELAY F1_0/20 static int nd_record_v_start_frame = -1; static int nd_record_v_frame_number = -1; static short nd_record_v_framebytes_written = 0; static int nd_record_v_recordframe = 1; static fix64 nd_record_v_recordframe_last_time = 0; static sbyte nd_record_v_no_space; static int nd_record_v_player_energy = -1; static int nd_record_v_player_shields = -1; static uint nd_record_v_player_flags = -1; static int nd_record_v_weapon_type = -1; static int nd_record_v_weapon_num = -1; static fix nd_record_v_homing_distance = -1; static int nd_record_v_primary_ammo = -1; static int nd_record_v_secondary_ammo = -1; void newdemo_record_oneframeevent_update(int wallupdate); extern int digi_link_sound_to_object3( int org_soundnum, short objnum, int forever, fix max_volume, fix max_distance, int loop_start, int loop_end ); extern window *game_setup(void); int newdemo_get_percent_done() { if ( Newdemo_state == ND_STATE_PLAYBACK ) { return (PHYSFS_tell(infile) * 100) / nd_playback_v_demosize; } if ( Newdemo_state == ND_STATE_RECORDING ) { return PHYSFS_tell(outfile); } return 0; } #define VEL_PRECISION 12 void my_extract_shortpos(object *objp, shortpos *spp) { int segnum; sbyte *sp; sp = spp->bytemat; objp->orient.rvec.x = *sp++ << MATRIX_PRECISION; objp->orient.uvec.x = *sp++ << MATRIX_PRECISION; objp->orient.fvec.x = *sp++ << MATRIX_PRECISION; objp->orient.rvec.y = *sp++ << MATRIX_PRECISION; objp->orient.uvec.y = *sp++ << MATRIX_PRECISION; objp->orient.fvec.y = *sp++ << MATRIX_PRECISION; objp->orient.rvec.z = *sp++ << MATRIX_PRECISION; objp->orient.uvec.z = *sp++ << MATRIX_PRECISION; objp->orient.fvec.z = *sp++ << MATRIX_PRECISION; segnum = spp->segment; objp->segnum = segnum; objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x; objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y; objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z; objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION); objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION); objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION); } int newdemo_read( void *buffer, int elsize, int nelem ) { int num_read; num_read = PHYSFS_read(infile, buffer, elsize, nelem); if (num_read < nelem || PHYSFS_eof(infile)) nd_playback_v_bad_read = -1; return num_read; } int newdemo_find_object( int signature ) { int i; object * objp; objp = Objects; for (i=0; i<=Highest_object_index; i++, objp++ ) { if ( (objp->type != OBJ_NONE) && (objp->signature == signature)) return i; } return -1; } int newdemo_write(const void *buffer, int elsize, int nelem ) { int num_written, total_size; total_size = elsize * nelem; nd_record_v_framebytes_written += total_size; Newdemo_num_written += total_size; Assert(outfile != NULL); num_written = PHYSFS_write(outfile, buffer, elsize, nelem); if (num_written == nelem && !nd_record_v_no_space) return num_written; nd_record_v_no_space=2; newdemo_stop_recording(); return -1; } /* * The next bunch of files taken from Matt's gamesave.c. We have to modify * these since the demo must save more information about objects that * just a gamesave */ static void nd_write_byte(sbyte b) { newdemo_write(&b, 1, 1); } static void nd_write_short(short s) { newdemo_write(&s, 2, 1); } static void nd_write_int(int i) { newdemo_write(&i, 4, 1); } static void nd_write_string(const char *str) { nd_write_byte(strlen(str) + 1); newdemo_write(str, strlen(str) + 1, 1); } static void nd_write_fix(fix f) { newdemo_write(&f, sizeof(fix), 1); } static void nd_write_fixang(fixang f) { newdemo_write(&f, sizeof(fixang), 1); } static void nd_write_vector(vms_vector *v) { nd_write_fix(v->x); nd_write_fix(v->y); nd_write_fix(v->z); } static void nd_write_angvec(vms_angvec *v) { nd_write_fixang(v->p); nd_write_fixang(v->b); nd_write_fixang(v->h); } void nd_write_shortpos(object *obj) { int i; shortpos sp; ubyte render_type; create_shortpos(&sp, obj, 0); render_type = obj->render_type; if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) { for (i = 0; i < 9; i++) nd_write_byte(sp.bytemat[i]); for (i = 0; i < 9; i++) { if (sp.bytemat[i] != 0) break; } if (i == 9) { Int3(); // contact Allender about this. } } nd_write_short(sp.xo); nd_write_short(sp.yo); nd_write_short(sp.zo); nd_write_short(sp.segment); nd_write_short(sp.velx); nd_write_short(sp.vely); nd_write_short(sp.velz); } static void nd_read_byte(sbyte *b) { newdemo_read(b, 1, 1); } static void nd_read_short(short *s) { newdemo_read(s, 2, 1); if (swap_endian) *s = SWAPSHORT(*s); } static void nd_read_int(int *i) { newdemo_read(i, 4, 1); if (swap_endian) *i = SWAPINT(*i); } static void nd_read_string(char *str) { sbyte len; nd_read_byte(&len); newdemo_read(str, len, 1); } static void nd_read_fix(fix *f) { newdemo_read(f, sizeof(fix), 1); if (swap_endian) *f = SWAPINT(*f); } static void nd_read_fixang(fixang *f) { newdemo_read(f, sizeof(fixang), 1); if (swap_endian) *f = SWAPSHORT(*f); } static void nd_read_vector(vms_vector *v) { nd_read_fix(&(v->x)); nd_read_fix(&(v->y)); nd_read_fix(&(v->z)); } static void nd_read_angvec(vms_angvec *v) { nd_read_fixang(&(v->p)); nd_read_fixang(&(v->b)); nd_read_fixang(&(v->h)); } static void nd_read_shortpos(object *obj) { shortpos sp; int i; ubyte render_type; memset(&sp,0,sizeof(shortpos)); render_type = obj->render_type; if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) { for (i = 0; i < 9; i++) nd_read_byte(&(sp.bytemat[i])); } nd_read_short(&(sp.xo)); nd_read_short(&(sp.yo)); nd_read_short(&(sp.zo)); nd_read_short(&(sp.segment)); nd_read_short(&(sp.velx)); nd_read_short(&(sp.vely)); nd_read_short(&(sp.velz)); my_extract_shortpos(obj, &sp); if ((obj->id == VCLIP_MORPHING_ROBOT) && (render_type == RT_FIREBALL) && (obj->control_type == CT_EXPLOSION)) extract_orient_from_segment(&obj->orient,&Segments[obj->segnum]); } object *prev_obj=NULL; //ptr to last object read in static int shareware = 0; // reading shareware demo? void nd_read_object(object *obj) { short shortsig = 0; memset(obj, 0, sizeof(object)); /* * Do render type first, since with render_type == RT_NONE, we * blow by all other object information */ nd_read_byte((sbyte *) &(obj->render_type)); nd_read_byte((sbyte *) &(obj->type)); if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA)) return; nd_read_byte((sbyte *) &(obj->id)); nd_read_byte((sbyte *) &(obj->flags)); nd_read_short(&shortsig); obj->signature = shortsig; // It's OKAY! We made sure, obj->signature is never has a value which short cannot handle!!! We cannot do this otherwise, without breaking the demo format! nd_read_shortpos(obj); obj->attached_obj = -1; switch(obj->type) { case OBJ_HOSTAGE: obj->control_type = CT_POWERUP; obj->movement_type = MT_NONE; obj->size = HOSTAGE_SIZE; break; case OBJ_ROBOT: obj->control_type = CT_AI; obj->movement_type = MT_PHYSICS; obj->size = Polygon_models[Robot_info[obj->id].model_num].rad; obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num; obj->rtype.pobj_info.subobj_flags = 0; obj->ctype.ai_info.CLOAKED = (Robot_info[obj->id].cloak_type?1:0); break; case OBJ_POWERUP: obj->control_type = CT_POWERUP; nd_read_byte((sbyte *) &(obj->movement_type)); // might have physics movement obj->size = Powerup_info[obj->id].size; break; case OBJ_PLAYER: obj->control_type = CT_NONE; obj->movement_type = MT_PHYSICS; obj->size = Polygon_models[Player_ship->model_num].rad; obj->rtype.pobj_info.model_num = Player_ship->model_num; obj->rtype.pobj_info.subobj_flags = 0; break; case OBJ_CLUTTER: obj->control_type = CT_NONE; obj->movement_type = MT_NONE; obj->size = Polygon_models[obj->id].rad; obj->rtype.pobj_info.model_num = obj->id; obj->rtype.pobj_info.subobj_flags = 0; break; default: nd_read_byte((sbyte *) &(obj->control_type)); nd_read_byte((sbyte *) &(obj->movement_type)); nd_read_fix(&(obj->size)); break; } nd_read_vector(&(obj->last_pos)); if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP)) nd_read_fix(&(obj->lifeleft)); else { sbyte b; // MWA old way -- won't work with big endian machines nd_read_byte((ubyte *)&(obj->lifeleft)); nd_read_byte(&b); obj->lifeleft = (fix)b; if (obj->lifeleft == -1) obj->lifeleft = IMMORTAL_TIME; else obj->lifeleft = (fix)((int)obj->lifeleft << 12); } if ((obj->type == OBJ_ROBOT) && !shareware) { if (Robot_info[obj->id].boss_flag) { sbyte cloaked; nd_read_byte(&cloaked); obj->ctype.ai_info.CLOAKED = cloaked; } } switch (obj->movement_type) { case MT_PHYSICS: nd_read_vector(&(obj->mtype.phys_info.velocity)); nd_read_vector(&(obj->mtype.phys_info.thrust)); break; case MT_SPINNING: nd_read_vector(&(obj->mtype.spin_rate)); break; case MT_NONE: break; default: Int3(); } switch (obj->control_type) { case CT_EXPLOSION: nd_read_fix(&(obj->ctype.expl_info.spawn_time)); nd_read_fix(&(obj->ctype.expl_info.delete_time)); nd_read_short(&(obj->ctype.expl_info.delete_objnum)); obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1; if (obj->flags & OF_ATTACHED) { //attach to previous object Assert(prev_obj!=NULL); if (prev_obj->control_type == CT_EXPLOSION) { if (prev_obj->flags & OF_ATTACHED && prev_obj->ctype.expl_info.attach_parent!=-1) obj_attach(&Objects[prev_obj->ctype.expl_info.attach_parent],obj); else obj->flags &= ~OF_ATTACHED; } else obj_attach(prev_obj,obj); } break; case CT_LIGHT: nd_read_fix(&(obj->ctype.light_info.intensity)); break; case CT_AI: case CT_WEAPON: case CT_NONE: case CT_FLYING: case CT_DEBRIS: case CT_POWERUP: case CT_SLEW: case CT_CNTRLCEN: case CT_REMOTE: case CT_MORPH: break; case CT_FLYTHROUGH: case CT_REPAIRCEN: default: Int3(); } switch (obj->render_type) { case RT_NONE: break; case RT_MORPH: case RT_POLYOBJ: { int i, tmo; if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) { nd_read_int(&(obj->rtype.pobj_info.model_num)); nd_read_int(&(obj->rtype.pobj_info.subobj_flags)); } if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS)) #if 0 for (i=0;ipobj_info.anim_angles[i])); #endif for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++) nd_read_angvec(&obj->rtype.pobj_info.anim_angles[i]); nd_read_int(&tmo); #ifndef EDITOR obj->rtype.pobj_info.tmap_override = tmo; #else if (tmo==-1) obj->rtype.pobj_info.tmap_override = -1; else { int xlated_tmo = tmap_xlate_table[tmo]; if (xlated_tmo < 0) { Int3(); xlated_tmo = 0; } obj->rtype.pobj_info.tmap_override = xlated_tmo; } #endif break; } case RT_POWERUP: case RT_WEAPON_VCLIP: case RT_FIREBALL: case RT_HOSTAGE: nd_read_int(&(obj->rtype.vclip_info.vclip_num)); nd_read_fix(&(obj->rtype.vclip_info.frametime)); nd_read_byte(&(obj->rtype.vclip_info.framenum)); break; case RT_LASER: break; default: Int3(); } prev_obj = obj; } void nd_write_object(object *obj) { int life; short shortsig = 0; /* * Do render_type first so on read, we can make determination of * what else to read in */ nd_write_byte(obj->render_type); nd_write_byte(obj->type); if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA)) return; nd_write_byte(obj->id); nd_write_byte(obj->flags); shortsig = obj->signature; // It's OKAY! We made sure, obj->signature is never has a value which short cannot handle!!! We cannot do this otherwise, without breaking the demo format! nd_write_short(shortsig); nd_write_shortpos(obj); if ((obj->type != OBJ_HOSTAGE) && (obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_POWERUP) && (obj->type != OBJ_CLUTTER)) { nd_write_byte(obj->control_type); nd_write_byte(obj->movement_type); nd_write_fix(obj->size); } if (obj->type == OBJ_POWERUP) nd_write_byte(obj->movement_type); nd_write_vector(&obj->last_pos); if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP)) nd_write_fix(obj->lifeleft); else { life = (int)obj->lifeleft; life = life >> 12; if (life > 255) life = 255; nd_write_byte((ubyte)life); } if (obj->type == OBJ_ROBOT) { if (Robot_info[obj->id].boss_flag) { if ((GameTime64 > Boss_cloak_start_time) && (GameTime64 < Boss_cloak_end_time)) nd_write_byte(1); else nd_write_byte(0); } } switch (obj->movement_type) { case MT_PHYSICS: nd_write_vector(&obj->mtype.phys_info.velocity); nd_write_vector(&obj->mtype.phys_info.thrust); break; case MT_SPINNING: nd_write_vector(&obj->mtype.spin_rate); break; case MT_NONE: break; default: Int3(); } switch (obj->control_type) { case CT_AI: break; case CT_EXPLOSION: nd_write_fix(obj->ctype.expl_info.spawn_time); nd_write_fix(obj->ctype.expl_info.delete_time); nd_write_short(obj->ctype.expl_info.delete_objnum); break; case CT_WEAPON: break; case CT_LIGHT: nd_write_fix(obj->ctype.light_info.intensity); break; case CT_NONE: case CT_FLYING: case CT_DEBRIS: case CT_POWERUP: case CT_SLEW: //the player is generally saved as slew case CT_CNTRLCEN: case CT_REMOTE: case CT_MORPH: break; case CT_REPAIRCEN: case CT_FLYTHROUGH: default: Int3(); } switch (obj->render_type) { case RT_NONE: break; case RT_MORPH: case RT_POLYOBJ: { int i; if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) { nd_write_int(obj->rtype.pobj_info.model_num); nd_write_int(obj->rtype.pobj_info.subobj_flags); } if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS)) #if 0 for (i=0;ipobj_info.anim_angles[i]); #endif for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++) nd_write_angvec(&obj->rtype.pobj_info.anim_angles[i]); nd_write_int(obj->rtype.pobj_info.tmap_override); break; } case RT_POWERUP: case RT_WEAPON_VCLIP: case RT_FIREBALL: case RT_HOSTAGE: nd_write_int(obj->rtype.vclip_info.vclip_num); nd_write_fix(obj->rtype.vclip_info.frametime); nd_write_byte(obj->rtype.vclip_info.framenum); break; case RT_LASER: break; default: Int3(); } } void newdemo_record_start_demo() { int i; nd_record_v_recordframe_last_time=GameTime64-REC_DELAY; // make sure first frame is recorded! stop_time(); nd_write_byte(ND_EVENT_START_DEMO); nd_write_byte(DEMO_VERSION); nd_write_byte(DEMO_GAME_TYPE); nd_write_fix(0); // NOTE: This is supposed to write GameTime (in fix). Since our GameTime64 is fix64 and the demos do not NEED this time actually, just write 0. #ifdef NETWORK if (Game_mode & GM_MULTI) nd_write_int(Game_mode | (Player_num << 16)); else #endif // NOTE LINK TO ABOVE!!! nd_write_int(Game_mode); #ifdef NETWORK if (Game_mode & GM_TEAM) { nd_write_byte(Netgame.team_vector); nd_write_string(Netgame.team_name[0]); nd_write_string(Netgame.team_name[1]); } if (Game_mode & GM_MULTI) { nd_write_byte((sbyte)N_players); for (i = 0; i < N_players; i++) { nd_write_string(Players[i].callsign); nd_write_byte(Players[i].connected); if (Game_mode & GM_MULTI_COOP) { nd_write_int(Players[i].score); } else { nd_write_short((short)Players[i].net_killed_total); nd_write_short((short)Players[i].net_kills_total); } } } else #endif // NOTE LINK TO ABOVE!!! nd_write_int(Players[Player_num].score); nd_record_v_weapon_type = -1; nd_record_v_weapon_num = -1; nd_record_v_homing_distance = -1; nd_record_v_primary_ammo = -1; nd_record_v_secondary_ammo = -1; for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) nd_write_short((short)Players[Player_num].primary_ammo[i]); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) nd_write_short((short)Players[Player_num].secondary_ammo[i]); nd_write_byte((sbyte)Players[Player_num].laser_level); // Support for missions added here nd_write_string(Current_mission_filename); nd_record_v_player_energy = (sbyte)(f2ir(Players[Player_num].energy)); nd_write_byte((sbyte)(f2ir(Players[Player_num].energy))); nd_record_v_player_shields = (sbyte)(f2ir(Players[Player_num].shields)); nd_write_byte((sbyte)(f2ir(Players[Player_num].shields))); nd_record_v_player_flags = Players[Player_num].flags; nd_write_int(Players[Player_num].flags); // be sure players flags are set nd_write_byte((sbyte)Primary_weapon); nd_write_byte((sbyte)Secondary_weapon); nd_record_v_start_frame = nd_record_v_frame_number = 0; newdemo_set_new_level(Current_level_num); newdemo_record_oneframeevent_update(1); start_time(); } void newdemo_record_start_frame(fix frame_time ) { if (nd_record_v_no_space) { newdemo_stop_playback(); return; } // Make demo recording waste a bit less space. // First check if if at least REC_DELAY has passed since last recorded frame. If yes, record frame and set nd_record_v_recordframe true. // nd_record_v_recordframe will be used for various other frame-by-frame events to drop some unnecessary bytes. // frame_time must be modified to get the right playback speed. if (nd_record_v_recordframe_last_time > GameTime64) nd_record_v_recordframe_last_time=GameTime64-REC_DELAY; if (nd_record_v_recordframe_last_time + REC_DELAY <= GameTime64 || frame_time >= REC_DELAY) { if (frame_time < REC_DELAY) frame_time = REC_DELAY; nd_record_v_recordframe_last_time = GameTime64-(GameTime64-(nd_record_v_recordframe_last_time + REC_DELAY)); nd_record_v_recordframe=1; stop_time(); nd_record_v_frame_number -= nd_record_v_start_frame; nd_write_byte(ND_EVENT_START_FRAME); nd_write_short(nd_record_v_framebytes_written - 1); // from previous frame nd_record_v_framebytes_written=3; nd_write_int(nd_record_v_frame_number); nd_record_v_frame_number++; nd_write_int(frame_time); start_time(); } else { nd_record_v_recordframe=0; } } void newdemo_record_render_object(object * obj) { if (!nd_record_v_recordframe) return; stop_time(); nd_write_byte(ND_EVENT_RENDER_OBJECT); nd_write_object(obj); start_time(); } void newdemo_record_viewer_object(object * obj) { if (!nd_record_v_recordframe) return; stop_time(); nd_write_byte(ND_EVENT_VIEWER_OBJECT); nd_write_object(obj); start_time(); } void newdemo_record_sound( int soundno ) { stop_time(); nd_write_byte(ND_EVENT_SOUND); nd_write_int( soundno ); start_time(); } void newdemo_record_sound_3d( int soundno, int angle, int volume ) { stop_time(); nd_write_byte( ND_EVENT_SOUND_3D ); nd_write_int( soundno ); nd_write_int( angle ); nd_write_int( volume ); start_time(); } void newdemo_record_sound_3d_once( int soundno, int angle, int volume ) { stop_time(); nd_write_byte( ND_EVENT_SOUND_3D_ONCE ); nd_write_int( soundno ); nd_write_int( angle ); nd_write_int( volume ); start_time(); } void newdemo_record_link_sound_to_object3( int soundno, short objnum, fix max_volume, fix max_distance, int loop_start, int loop_end ) { stop_time(); nd_write_byte( ND_EVENT_LINK_SOUND_TO_OBJ ); nd_write_int( soundno ); nd_write_int( Objects[objnum].signature ); nd_write_int( max_volume ); nd_write_int( max_distance ); nd_write_int( loop_start ); nd_write_int( loop_end ); start_time(); } void newdemo_record_kill_sound_linked_to_object( int objnum ) { stop_time(); nd_write_byte( ND_EVENT_KILL_SOUND_TO_OBJ ); nd_write_int( Objects[objnum].signature ); start_time(); } void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum ) { stop_time(); nd_write_byte( ND_EVENT_WALL_HIT_PROCESS ); nd_write_int( segnum ); nd_write_int( side ); nd_write_int( damage ); nd_write_int( playernum ); start_time(); } void newdemo_record_hostage_rescued( int hostage_number ) { stop_time(); nd_write_byte( ND_EVENT_HOSTAGE_RESCUED ); nd_write_int( hostage_number ); start_time(); } void newdemo_record_morph_frame(morph_data *md) { if (!nd_record_v_recordframe) return; stop_time(); nd_write_byte( ND_EVENT_MORPH_FRAME ); nd_write_object( md->obj ); start_time(); } void newdemo_record_wall_toggle( int segnum, int side ) { stop_time(); nd_write_byte( ND_EVENT_WALL_TOGGLE ); nd_write_int( segnum ); nd_write_int( side ); start_time(); } void newdemo_record_control_center_destroyed() { if (!nd_record_v_recordframe) return; stop_time(); nd_write_byte( ND_EVENT_CONTROL_CENTER_DESTROYED ); nd_write_int( Countdown_seconds_left ); start_time(); } void newdemo_record_hud_message(const char * message ) { stop_time(); nd_write_byte( ND_EVENT_HUD_MESSAGE ); nd_write_string(message); start_time(); } void newdemo_record_palette_effect(short r, short g, short b ) { if (!nd_record_v_recordframe) return; stop_time(); nd_write_byte( ND_EVENT_PALETTE_EFFECT ); nd_write_short( r ); nd_write_short( g ); nd_write_short( b ); start_time(); } void newdemo_record_player_energy(int energy) { if (nd_record_v_player_energy == energy) return; stop_time(); nd_write_byte( ND_EVENT_PLAYER_ENERGY ); nd_write_byte((sbyte) nd_record_v_player_energy); nd_write_byte((sbyte) energy); nd_record_v_player_energy = energy; start_time(); } void newdemo_record_player_shields(int shield) { if (nd_record_v_player_shields == shield) return; stop_time(); nd_write_byte( ND_EVENT_PLAYER_SHIELD ); nd_write_byte((sbyte)nd_record_v_player_shields); nd_write_byte((sbyte)shield); nd_record_v_player_shields = shield; start_time(); } void newdemo_record_player_flags(uint flags) { if (nd_record_v_player_flags == flags) return; stop_time(); nd_write_byte( ND_EVENT_PLAYER_FLAGS ); nd_write_int(((short)nd_record_v_player_flags << 16) | (short)flags); nd_record_v_player_flags = flags; start_time(); } void newdemo_record_player_weapon(int weapon_type, int weapon_num) { if (nd_record_v_weapon_type == weapon_type && nd_record_v_weapon_num == weapon_num) return; stop_time(); nd_write_byte( ND_EVENT_PLAYER_WEAPON ); nd_write_byte((sbyte)weapon_type); nd_write_byte((sbyte)weapon_num); if (weapon_type) nd_write_byte((sbyte)Secondary_weapon); else nd_write_byte((sbyte)Primary_weapon); nd_record_v_weapon_type = weapon_type; nd_record_v_weapon_num = weapon_num; start_time(); } void newdemo_record_effect_blowup(short segment, int side, vms_vector *pnt) { stop_time(); nd_write_byte (ND_EVENT_EFFECT_BLOWUP); nd_write_short(segment); nd_write_byte((sbyte)side); nd_write_vector(pnt); start_time(); } void newdemo_record_homing_distance(fix distance) { if ((nd_record_v_homing_distance>>16) == (distance>>16)) return; stop_time(); nd_write_byte(ND_EVENT_HOMING_DISTANCE); nd_write_short((short)(distance>>16)); nd_record_v_homing_distance = distance; start_time(); } void newdemo_record_letterbox(void) { stop_time(); nd_write_byte(ND_EVENT_LETTERBOX); start_time(); } void newdemo_record_rearview(void) { stop_time(); nd_write_byte(ND_EVENT_REARVIEW); start_time(); } void newdemo_record_restore_cockpit(void) { stop_time(); nd_write_byte(ND_EVENT_RESTORE_COCKPIT); start_time(); } void newdemo_record_restore_rearview(void) { stop_time(); nd_write_byte(ND_EVENT_RESTORE_REARVIEW); start_time(); } void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap) { stop_time(); nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM1); nd_write_short(seg); nd_write_byte(side); nd_write_short(cseg); nd_write_byte(cside); nd_write_short(tmap); start_time(); } void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap) { stop_time(); nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM2); nd_write_short(seg); nd_write_byte(side); nd_write_short(cseg); nd_write_byte(cside); nd_write_short(tmap); start_time(); } void newdemo_record_multi_cloak(int pnum) { stop_time(); nd_write_byte(ND_EVENT_MULTI_CLOAK); nd_write_byte((sbyte)pnum); start_time(); } void newdemo_record_multi_decloak(int pnum) { stop_time(); nd_write_byte(ND_EVENT_MULTI_DECLOAK); nd_write_byte((sbyte)pnum); start_time(); } void newdemo_record_multi_death(int pnum) { stop_time(); nd_write_byte(ND_EVENT_MULTI_DEATH); nd_write_byte((sbyte)pnum); start_time(); } void newdemo_record_multi_kill(int pnum, sbyte kill) { stop_time(); nd_write_byte(ND_EVENT_MULTI_KILL); nd_write_byte((sbyte)pnum); nd_write_byte(kill); start_time(); } void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign) { stop_time(); nd_write_byte(ND_EVENT_MULTI_CONNECT); nd_write_byte((sbyte)pnum); nd_write_byte((sbyte)new_player); if (!new_player) { nd_write_string(Players[pnum].callsign); nd_write_int(Players[pnum].net_killed_total); nd_write_int(Players[pnum].net_kills_total); } nd_write_string(new_callsign); start_time(); } void newdemo_record_multi_reconnect(int pnum) { stop_time(); nd_write_byte(ND_EVENT_MULTI_RECONNECT); nd_write_byte((sbyte)pnum); start_time(); } void newdemo_record_multi_disconnect(int pnum) { stop_time(); nd_write_byte(ND_EVENT_MULTI_DISCONNECT); nd_write_byte((sbyte)pnum); start_time(); } void newdemo_record_player_score(int score) { stop_time(); nd_write_byte(ND_EVENT_PLAYER_SCORE); nd_write_int(score); start_time(); } void newdemo_record_multi_score(int pnum, int score) { stop_time(); nd_write_byte(ND_EVENT_MULTI_SCORE); nd_write_byte((sbyte)pnum); nd_write_int(score - Players[pnum].score); // called before score is changed!!!! start_time(); } void newdemo_record_primary_ammo(int new_ammo) { if (nd_record_v_primary_ammo == new_ammo) return; stop_time(); nd_write_byte(ND_EVENT_PRIMARY_AMMO); if (nd_record_v_primary_ammo < 0) nd_write_short((short)new_ammo); else nd_write_short((short)nd_record_v_primary_ammo); nd_write_short((short)new_ammo); nd_record_v_primary_ammo = new_ammo; start_time(); } void newdemo_record_secondary_ammo(int new_ammo) { if (nd_record_v_secondary_ammo == new_ammo) return; stop_time(); nd_write_byte(ND_EVENT_SECONDARY_AMMO); if (nd_record_v_secondary_ammo < 0) nd_write_short((short)new_ammo); else nd_write_short((short)nd_record_v_secondary_ammo); nd_write_short((short)new_ammo); nd_record_v_secondary_ammo = new_ammo; start_time(); } void newdemo_record_door_opening(int segnum, int side) { stop_time(); nd_write_byte(ND_EVENT_DOOR_OPENING); nd_write_short((short)segnum); nd_write_byte((sbyte)side); start_time(); } void newdemo_record_laser_level(sbyte old_level, sbyte new_level) { stop_time(); nd_write_byte(ND_EVENT_LASER_LEVEL); nd_write_byte(old_level); nd_write_byte(new_level); start_time(); } void newdemo_set_new_level(int level_num) { stop_time(); nd_write_byte(ND_EVENT_NEW_LEVEL); nd_write_byte((sbyte)level_num); nd_write_byte((sbyte)Current_level_num); start_time(); } /* * By design, the demo code does not record certain events when demo recording starts or ends. * To not break compability this function can be applied at start/end of demo recording to * re-record these events. It will "simulate" those events without using functions older game * versions cannot handle. */ void newdemo_record_oneframeevent_update(int wallupdate) { int i = 0; if (Player_is_dead) newdemo_record_letterbox(); else newdemo_record_restore_cockpit(); if (Rear_view) newdemo_record_rearview(); else newdemo_record_restore_rearview(); // This will record tmaps for all walls and properly show doors which were opened before demo recording started. if (wallupdate) { for (i = 0; i < Num_walls; i++) { int side; segment *seg; seg = &Segments[Walls[i].segnum]; side = Walls[i].sidenum; // actually this is kinda stupid: when playing ther same tmap will be put on front and back side of the wall ... for doors this is stupid so just record the front side which will do for doors just fine ... if (seg->sides[side].tmap_num != 0) newdemo_record_wall_set_tmap_num1(Walls[i].segnum,side,Walls[i].segnum,side,seg->sides[side].tmap_num); if (seg->sides[side].tmap_num2 != 0) newdemo_record_wall_set_tmap_num2(Walls[i].segnum,side,Walls[i].segnum,side,seg->sides[side].tmap_num2); } } } enum purpose_type { PURPOSE_CHOSE_PLAY = 0, PURPOSE_RANDOM_PLAY, PURPOSE_REWRITE }; int newdemo_read_demo_start(enum purpose_type purpose) { sbyte i=0, version=0, game_type=0, laser_level=0, c=0; ubyte energy=0, shield=0; char current_mission[9]; fix nd_GameTime32 = 0; Rear_view=0; shareware = 0; nd_read_byte(&c); if (purpose == PURPOSE_REWRITE) nd_write_byte(c); if ((c != ND_EVENT_START_DEMO) || nd_playback_v_bad_read) { nm_messagebox( NULL, 1, TXT_OK, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_CORRUPT ); return 1; } nd_read_byte(&version); if (purpose == PURPOSE_REWRITE) nd_write_byte(version); if (version == DEMO_VERSION_SHAREWARE) shareware = 1; else if (version < DEMO_VERSION) { if (purpose == PURPOSE_CHOSE_PLAY) { nm_messagebox( NULL, 1, TXT_OK, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD ); } return 1; } nd_read_byte(&game_type); if (purpose == PURPOSE_REWRITE) nd_write_byte(game_type); if ((game_type == DEMO_GAME_TYPE_SHAREWARE) && shareware) shareware = shareware; // all good else if (game_type != DEMO_GAME_TYPE) { nm_messagebox( NULL, 1, TXT_OK, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD ); return 1; } nd_read_fix(&nd_GameTime32); // NOTE: Demos write GameTime in fix. GameTime64 = nd_GameTime32; nd_read_int(&Newdemo_game_mode); #ifndef NETWORK if (Newdemo_game_mode & GM_MULTI) { nm_messagebox( NULL, 1, "Ok", "can't playback net game\nwith this version of code\n" ); return 1; } #endif #ifdef NETWORK change_playernum_to((Newdemo_game_mode >> 16) & 0x7); if (shareware) { if (Newdemo_game_mode & GM_TEAM) { nd_read_byte((sbyte *)&(Netgame.team_vector)); if (purpose == PURPOSE_REWRITE) nd_write_byte(Netgame.team_vector); } for (i =0 ; i < MAX_PLAYERS; i++) { Players[i].cloak_time = 0; Players[i].invulnerable_time = 0; } } else { if (Newdemo_game_mode & GM_TEAM) { nd_read_byte((sbyte *) &(Netgame.team_vector)); nd_read_string(Netgame.team_name[0]); nd_read_string(Netgame.team_name[1]); if (purpose == PURPOSE_REWRITE) { nd_write_byte(Netgame.team_vector); nd_write_string(Netgame.team_name[0]); nd_write_string(Netgame.team_name[1]); } } if (Newdemo_game_mode & GM_MULTI) { if (purpose != PURPOSE_REWRITE) multi_new_game(); nd_read_byte(&c); N_players = (int)c; // changed this to above two lines -- breaks on the mac because of // endian issues // nd_read_byte((sbyte *)&N_players); if (purpose == PURPOSE_REWRITE) nd_write_byte(N_players); for (i = 0 ; i < N_players; i++) { Players[i].cloak_time = 0; Players[i].invulnerable_time = 0; nd_read_string(Players[i].callsign); nd_read_byte(&(Players[i].connected)); if (purpose == PURPOSE_REWRITE) { nd_write_string(Players[i].callsign); nd_write_byte(Players[i].connected); } if (Newdemo_game_mode & GM_MULTI_COOP) { nd_read_int(&(Players[i].score)); if (purpose == PURPOSE_REWRITE) nd_write_int(Players[i].score); } else { nd_read_short((short *)&(Players[i].net_killed_total)); nd_read_short((short *)&(Players[i].net_kills_total)); if (purpose == PURPOSE_REWRITE) { nd_write_short(Players[i].net_killed_total); nd_write_short(Players[i].net_kills_total); } } } Game_mode = Newdemo_game_mode; if (purpose != PURPOSE_REWRITE) multi_sort_kill_list(); Game_mode = GM_NORMAL; } } #endif #ifdef NETWORK if (!(Newdemo_game_mode & GM_MULTI)) #endif { nd_read_int(&(Players[Player_num].score)); // Note link to above if! if (purpose == PURPOSE_REWRITE) nd_write_int(Players[Player_num].score); } for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) { nd_read_short((short*)&(Players[Player_num].primary_ammo[i])); if (purpose == PURPOSE_REWRITE) nd_write_short(Players[Player_num].primary_ammo[i]); } for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) { nd_read_short((short*)&(Players[Player_num].secondary_ammo[i])); if (purpose == PURPOSE_REWRITE) nd_write_short(Players[Player_num].secondary_ammo[i]); } nd_read_byte(&laser_level); if ((purpose != PURPOSE_REWRITE) && (laser_level != Players[Player_num].laser_level)) { Players[Player_num].laser_level = laser_level; update_laser_weapon_info(); } else if (purpose == PURPOSE_REWRITE) nd_write_byte(laser_level); // Support for missions nd_read_string(current_mission); if (purpose == PURPOSE_REWRITE) nd_write_string(current_mission); if (!shareware) { #ifdef DEST_SAT if (!strcmp(current_mission, "")) strcpy(current_mission, "DESTSAT"); #endif if ((purpose != PURPOSE_REWRITE) && !load_mission_by_name(current_mission)) { if (purpose == PURPOSE_CHOSE_PLAY) { nm_messagebox( NULL, 1, TXT_OK, TXT_NOMISSION4DEMO, current_mission ); } return 1; } } //#endif nd_recorded_total = 0; nd_playback_total = 0; nd_read_byte((sbyte*)&energy); nd_read_byte((sbyte*)&shield); if (purpose == PURPOSE_REWRITE) { nd_write_byte(energy); nd_write_byte(shield); } nd_read_int((int *)&(Players[Player_num].flags)); if (purpose == PURPOSE_REWRITE) nd_write_int(Players[Player_num].flags); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { Players[Player_num].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) Players[Player_num].invulnerable_time = GameTime64 - (INVULNERABLE_TIME_MAX / 2); nd_read_byte((sbyte *)&Primary_weapon); nd_read_byte((sbyte *)&Secondary_weapon); if (purpose == PURPOSE_REWRITE) { nd_write_byte(Primary_weapon); nd_write_byte(Secondary_weapon); } // Next bit of code to fix problem that I introduced between 1.0 and 1.1 // check the next byte -- it _will_ be a load_new_level event. If it is // not, then we must shift all bytes up by one. if (shareware) { unsigned char c; nd_read_byte((sbyte *)&c); if (c != ND_EVENT_NEW_LEVEL) { int flags; flags = Players[Player_num].flags; energy = shield; shield = (unsigned char)flags; flags = (flags >> 8) & 0x00ffffff; flags |= (Primary_weapon << 24); Primary_weapon = Secondary_weapon; Secondary_weapon = c; } else PHYSFS_seek(infile, PHYSFS_tell(infile) - 1); } Players[Player_num].energy = i2f(energy); Players[Player_num].shields = i2f(shield); return 0; } void newdemo_pop_ctrlcen_triggers() { int anim_num, n, i; int side, cside; segment *seg, *csegp; for (i = 0; i < ControlCenterTriggers.num_links; i++) { seg = &Segments[ControlCenterTriggers.seg[i]]; side = ControlCenterTriggers.side[i]; csegp = &Segments[seg->children[side]]; cside = find_connect_side(seg, csegp); anim_num = Walls[seg->sides[side].wall_num].clip_num; n = WallAnims[anim_num].num_frames; if (WallAnims[anim_num].flags & WCF_TMAP1) { seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[n-1]; } else { seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[n-1]; } } } int newdemo_read_frame_information(int rewrite) { int done, segnum, side, objnum, soundno, angle, volume, i; object *obj; sbyte c; done = 0; if (Newdemo_vcr_state != ND_STATE_PAUSED) for (segnum=0; segnum <= Highest_segment_index; segnum++) Segments[segnum].objects = -1; reset_objects(1); Players[Player_num].homing_object_dist = -F1_0; prev_obj = NULL; while( !done ) { nd_read_byte(&c); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite && (c != ND_EVENT_EOF)) nd_write_byte(c); switch( c ) { case ND_EVENT_START_FRAME: { // Followed by an integer frame number, then a fix FrameTime short last_frame_length; done=1; nd_read_short(&last_frame_length); nd_read_int(&nd_playback_v_framecount); nd_read_int((int *)&nd_recorded_time); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_short(last_frame_length); nd_record_v_framebytes_written = 3; nd_write_int(nd_playback_v_framecount); nd_write_int(nd_recorded_time); break; } if (Newdemo_vcr_state == ND_STATE_PLAYBACK) nd_recorded_total += nd_recorded_time; nd_playback_v_framecount--; break; } case ND_EVENT_VIEWER_OBJECT: // Followed by an object structure nd_read_object(Viewer); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_object(Viewer); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) { segnum = Viewer->segnum; Viewer->next = Viewer->prev = Viewer->segnum = -1; // HACK HACK HACK -- since we have multiple level recording, it can be the case // HACK HACK HACK -- that when rewinding the demo, the viewer is in a segment // HACK HACK HACK -- that is greater than the highest index of segments. Bash // HACK HACK HACK -- the viewer to segment 0 for bogus view. if (segnum > Highest_segment_index) segnum = 0; obj_link(Viewer-Objects,segnum); } break; case ND_EVENT_RENDER_OBJECT: // Followed by an object structure objnum = obj_allocate(); if (objnum==-1) break; obj = &Objects[objnum]; nd_read_object(obj); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_object(obj); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) { segnum = obj->segnum; obj->next = obj->prev = obj->segnum = -1; // HACK HACK HACK -- don't render objects is segments greater than Highest_segment_index // HACK HACK HACK -- (see above) if (segnum > Highest_segment_index) break; obj_link(obj-Objects,segnum); #ifdef NETWORK if ((obj->type == OBJ_PLAYER) && (Newdemo_game_mode & GM_MULTI)) { int player; if (Newdemo_game_mode & GM_TEAM) player = get_team(obj->id); else player = obj->id; if (player == 0) break; player--; for (i=0;irtype.pobj_info.model_num].n_textures;i++) multi_player_textures[player][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[obj->rtype.pobj_info.model_num].first_texture+i]]; multi_player_textures[player][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2]]; multi_player_textures[player][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2+1]]; obj->rtype.pobj_info.alt_textures = player+1; } #endif } break; case ND_EVENT_SOUND: nd_read_int(&soundno); if (nd_playback_v_bad_read) {done = -1; break; } if (rewrite) { nd_write_int(soundno); break; } if (Newdemo_vcr_state == ND_STATE_PLAYBACK) digi_play_sample( soundno, F1_0 ); break; case ND_EVENT_SOUND_3D: nd_read_int(&soundno); nd_read_int(&angle); nd_read_int(&volume); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(soundno); nd_write_int(angle); nd_write_int(volume); break; } if (Newdemo_vcr_state == ND_STATE_PLAYBACK) digi_play_sample_3d( soundno, angle, volume, 0 ); break; case ND_EVENT_SOUND_3D_ONCE: nd_read_int(&soundno); nd_read_int(&angle); nd_read_int(&volume); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(soundno); nd_write_int(angle); nd_write_int(volume); break; } if (Newdemo_vcr_state == ND_STATE_PLAYBACK) digi_play_sample_3d( soundno, angle, volume, 1 ); break; case ND_EVENT_LINK_SOUND_TO_OBJ: { int soundno, objnum, max_volume, max_distance, loop_start, loop_end; int signature; nd_read_int( &soundno ); nd_read_int( &signature ); nd_read_int( &max_volume ); nd_read_int( &max_distance ); nd_read_int( &loop_start ); nd_read_int( &loop_end ); if (rewrite) { nd_write_int( soundno ); nd_write_int( signature ); nd_write_int( max_volume ); nd_write_int( max_distance ); nd_write_int( loop_start ); nd_write_int( loop_end ); break; } objnum = newdemo_find_object( signature ); if ( objnum > -1 && Newdemo_vcr_state == ND_STATE_PLAYBACK) { // @mk, 2/22/96, John told me to. digi_link_sound_to_object3( soundno, objnum, 1, max_volume, max_distance, loop_start, loop_end ); } } break; case ND_EVENT_KILL_SOUND_TO_OBJ: { int objnum, signature; nd_read_int( &signature ); if (rewrite) { nd_write_int( signature ); break; } objnum = newdemo_find_object( signature ); if ( objnum > -1 && Newdemo_vcr_state == ND_STATE_PLAYBACK) { // @mk, 2/22/96, John told me to. digi_kill_sound_linked_to_object(objnum); } } break; case ND_EVENT_WALL_HIT_PROCESS: { int player, segnum; fix damage; nd_read_int(&segnum); nd_read_int(&side); nd_read_fix(&damage); nd_read_int(&player); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(segnum); nd_write_int(side); nd_write_fix(damage); nd_write_int(player); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) wall_hit_process(&Segments[segnum], side, damage, player, &(Objects[0]) ); break; } case ND_EVENT_TRIGGER: nd_read_int(&segnum); nd_read_int(&side); nd_read_int(&objnum); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(segnum); nd_write_int(side); nd_write_int(objnum); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) check_trigger(&Segments[segnum], side, objnum, 0); break; case ND_EVENT_HOSTAGE_RESCUED: { int hostage_number; nd_read_int(&hostage_number); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(hostage_number); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) hostage_rescue( hostage_number ); break; } case ND_EVENT_MORPH_FRAME: { #if 0 morph_data *md; md = &morph_objects[0]; if (newdemo_read( md->morph_vecs, sizeof(md->morph_vecs), 1 )!=1) { done=-1; break; } if (newdemo_read( md->submodel_active, sizeof(md->submodel_active), 1 )!=1) { done=-1; break; } if (newdemo_read( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 )!=1) { done=-1; break; } #endif objnum = obj_allocate(); if (objnum==-1) break; obj = &Objects[objnum]; nd_read_object(obj); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_object(obj); break; } obj->render_type = RT_POLYOBJ; if (Newdemo_vcr_state != ND_STATE_PAUSED) { if (Newdemo_vcr_state != ND_STATE_PAUSED) { segnum = obj->segnum; obj->next = obj->prev = obj->segnum = -1; obj_link(obj-Objects,segnum); } } break; } case ND_EVENT_WALL_TOGGLE: nd_read_int(&segnum); nd_read_int(&side); if (nd_playback_v_bad_read) {done = -1; break; } if (rewrite) { nd_write_int(segnum); nd_write_int(side); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) wall_toggle(segnum, side); break; case ND_EVENT_CONTROL_CENTER_DESTROYED: nd_read_int(&Countdown_seconds_left); Control_center_destroyed = 1; if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_int(Countdown_seconds_left); break; } if (!nd_playback_v_cntrlcen_destroyed) { newdemo_pop_ctrlcen_triggers(); nd_playback_v_cntrlcen_destroyed = 1; } break; case ND_EVENT_HUD_MESSAGE: { char hud_msg[60]; nd_read_string(&(hud_msg[0])); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_string(&(hud_msg[0])); break; } #if 0 // adb: would cause noise for non-D1X... if (hud_msg[0] == '\x01') class = ((unsigned char)hud_msg[1]) | (((unsigned char)hud_msg[2]) << 8) | (((unsigned char)hud_msg[3]) << 16) | (((unsigned char)hud_msg[4]) << 24); #endif if (Newdemo_vcr_state != ND_STATE_PAUSED) HUD_init_message_literal( HM_DEFAULT, hud_msg ); break; } case ND_EVENT_PALETTE_EFFECT: { short r, g, b; nd_read_short(&r); nd_read_short(&g); nd_read_short(&b); if (nd_playback_v_bad_read) { done = -1; break; } if (rewrite) { nd_write_short(r); nd_write_short(g); nd_write_short(b); break; } PALETTE_FLASH_SET(r,g,b); break; } case ND_EVENT_PLAYER_ENERGY: { ubyte energy; ubyte old_energy; if (!shareware) { nd_read_byte((sbyte *)&old_energy); if (rewrite) nd_write_byte(old_energy); } nd_read_byte((sbyte *)&energy); if (nd_playback_v_bad_read) {done = -1; break; } if (rewrite) { nd_write_byte(energy); break; } if (shareware) Players[Player_num].energy = i2f(energy); else { if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[Player_num].energy = i2f(energy); } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { if (old_energy != 255) Players[Player_num].energy = i2f(old_energy); } } break; } case ND_EVENT_PLAYER_SHIELD: { ubyte shield; ubyte old_shield; if (!shareware) { nd_read_byte((sbyte *)&old_shield); if (rewrite) nd_write_byte(old_shield); } nd_read_byte((sbyte *)&shield); if (nd_playback_v_bad_read) {done = -1; break; } if (rewrite) { nd_write_byte(shield); break; } if (shareware) Players[Player_num].shields = i2f(shield); else { if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[Player_num].shields = i2f(shield); } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { if (old_shield != 255) Players[Player_num].shields = i2f(old_shield); } } break; } case ND_EVENT_PLAYER_FLAGS: { uint oflags; nd_read_int((int *)&(Players[Player_num].flags)); if (nd_playback_v_bad_read) {done = -1; break; } if (rewrite) { nd_write_int(Players[Player_num].flags); break; } oflags = Players[Player_num].flags >> 16; Players[Player_num].flags &= 0xffff; if ((Newdemo_vcr_state == ND_STATE_REWINDING) || ((Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) && (oflags != 0xffff)) ) { if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) { Players[Player_num].cloak_time = 0; } if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) { Players[Player_num].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) Players[Player_num].invulnerable_time = 0; if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) Players[Player_num].invulnerable_time = GameTime64 - (INVULNERABLE_TIME_MAX / 2); Players[Player_num].flags = oflags; } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) { Players[Player_num].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) { Players[Player_num].cloak_time = 0; } if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) Players[Player_num].invulnerable_time = GameTime64 - (INVULNERABLE_TIME_MAX / 2); if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)) Players[Player_num].invulnerable_time = 0; } update_laser_weapon_info(); // in case of quad laser change break; } case ND_EVENT_PLAYER_WEAPON: if (shareware) { ubyte weapon_type, weapon_num; nd_read_byte((sbyte *)&weapon_type); nd_read_byte((sbyte *)&weapon_num); if (rewrite) { nd_write_byte(weapon_type); nd_write_byte(weapon_num); break; } if (weapon_type == 0) Primary_weapon = (int)weapon_num; else Secondary_weapon = (int)weapon_num; break; } else { ubyte weapon_type, weapon_num; ubyte old_weapon; nd_read_byte((sbyte *)&weapon_type); nd_read_byte((sbyte *)&weapon_num); nd_read_byte((sbyte *)&old_weapon); if (rewrite) { nd_write_byte(weapon_type); nd_write_byte(weapon_num); nd_write_byte(old_weapon); break; } if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { if (weapon_type == 0) Primary_weapon = (int)weapon_num; else Secondary_weapon = (int)weapon_num; } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { if (weapon_type == 0) Primary_weapon = (int)old_weapon; else Secondary_weapon = (int)old_weapon; } break; } case ND_EVENT_EFFECT_BLOWUP: { short segnum; sbyte side; vms_vector pnt; nd_read_short(&segnum); nd_read_byte(&side); nd_read_vector(&pnt); if (rewrite) { nd_write_short(segnum); nd_write_byte(side); nd_write_vector(&pnt); break; } if (Newdemo_vcr_state != ND_STATE_PAUSED) check_effect_blowup(&(Segments[segnum]), side, &pnt); break; } case ND_EVENT_HOMING_DISTANCE: { short distance; nd_read_short(&distance); if (rewrite) { nd_write_short(distance); break; } Players[Player_num].homing_object_dist = i2f((int)(distance << 16)); break; } case ND_EVENT_LETTERBOX: if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { nd_playback_v_dead = 1; } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) nd_playback_v_dead = 0; break; case ND_EVENT_REARVIEW: if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { nd_playback_v_rear = 1; } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { nd_playback_v_rear = 0; } break; case ND_EVENT_RESTORE_COCKPIT: if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { nd_playback_v_dead = 1; } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) nd_playback_v_dead = 0; break; case ND_EVENT_RESTORE_REARVIEW: if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { nd_playback_v_rear = 1; } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { nd_playback_v_rear = 0; } break; case ND_EVENT_WALL_SET_TMAP_NUM1: { short seg, cseg, tmap; sbyte side,cside; nd_read_short(&seg); nd_read_byte(&side); nd_read_short(&cseg); nd_read_byte(&cside); nd_read_short( &tmap ); if (rewrite) { nd_write_short(seg); nd_write_byte(side); nd_write_short(cseg); nd_write_byte(cside); nd_write_short(tmap); break; } if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) Segments[seg].sides[side].tmap_num = Segments[cseg].sides[cside].tmap_num = tmap; break; } case ND_EVENT_WALL_SET_TMAP_NUM2: { short seg, cseg, tmap; sbyte side,cside; nd_read_short(&seg); nd_read_byte(&side); nd_read_short(&cseg); nd_read_byte(&cside); nd_read_short( &tmap ); if (rewrite) { nd_write_short(seg); nd_write_byte(side); nd_write_short(cseg); nd_write_byte(cside); nd_write_short(tmap); break; } if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) { Assert(tmap!=0 && Segments[seg].sides[side].tmap_num2!=0); Segments[seg].sides[side].tmap_num2 = Segments[cseg].sides[cside].tmap_num2 = tmap; } break; } case ND_EVENT_MULTI_CLOAK: { sbyte pnum; nd_read_byte(&pnum); if (rewrite) { nd_write_byte(pnum); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = 0; } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[pnum].flags |= PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } break; } case ND_EVENT_MULTI_DECLOAK: { sbyte pnum; nd_read_byte(&pnum); if (rewrite) { nd_write_byte(pnum); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { Players[pnum].flags |= PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = 0; } break; } case ND_EVENT_MULTI_DEATH: { sbyte pnum; nd_read_byte(&pnum); if (rewrite) { nd_write_byte(pnum); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[pnum].net_killed_total--; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[pnum].net_killed_total++; break; } #ifdef NETWORK case ND_EVENT_MULTI_KILL: { sbyte pnum, kill; nd_read_byte(&pnum); nd_read_byte(&kill); if (rewrite) { nd_write_byte(pnum); nd_write_byte(kill); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { Players[pnum].net_kills_total -= kill; if (Newdemo_game_mode & GM_TEAM) team_kills[get_team(pnum)] -= kill; } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[pnum].net_kills_total += kill; if (Newdemo_game_mode & GM_TEAM) team_kills[get_team(pnum)] += kill; } Game_mode = Newdemo_game_mode; multi_sort_kill_list(); Game_mode = GM_NORMAL; break; } case ND_EVENT_MULTI_CONNECT: { sbyte pnum, new_player; int killed_total, kills_total; char new_callsign[CALLSIGN_LEN+1], old_callsign[CALLSIGN_LEN+1]; nd_read_byte(&pnum); nd_read_byte(&new_player); if (!new_player) { nd_read_string(old_callsign); nd_read_int(&killed_total); nd_read_int(&kills_total); } nd_read_string(new_callsign); if (rewrite) { nd_write_byte(pnum); nd_write_byte(new_player); if (!new_player) { nd_write_string(old_callsign); nd_write_int(killed_total); nd_write_int(kills_total); } nd_write_string(new_callsign); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { Players[pnum].connected = CONNECT_DISCONNECTED; if (!new_player) { memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1); Players[pnum].net_killed_total = killed_total; Players[pnum].net_kills_total = kills_total; } else { N_players--; } } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[pnum].connected = CONNECT_PLAYING; Players[pnum].net_kills_total = 0; Players[pnum].net_killed_total = 0; memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1); if (new_player) N_players++; } break; } case ND_EVENT_MULTI_RECONNECT: { sbyte pnum; nd_read_byte(&pnum); if (rewrite) { nd_write_byte(pnum); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[pnum].connected = CONNECT_DISCONNECTED; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[pnum].connected = CONNECT_PLAYING; break; } case ND_EVENT_MULTI_DISCONNECT: { sbyte pnum; nd_read_byte(&pnum); if (rewrite) { nd_write_byte(pnum); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[pnum].connected = CONNECT_DISCONNECTED; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[pnum].connected = CONNECT_PLAYING; break; } case ND_EVENT_MULTI_SCORE: { int score; sbyte pnum; nd_read_byte(&pnum); nd_read_int(&score); if (rewrite) { nd_write_byte(pnum); nd_write_int(score); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[pnum].score -= score; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[pnum].score += score; Game_mode = Newdemo_game_mode; multi_sort_kill_list(); Game_mode = GM_NORMAL; break; } #endif // NETWORK case ND_EVENT_PLAYER_SCORE: { int score; nd_read_int(&score); if (rewrite) { nd_write_int(score); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[Player_num].score -= score; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[Player_num].score += score; break; } case ND_EVENT_PRIMARY_AMMO: { unsigned short old_ammo, new_ammo; nd_read_short((short *)&old_ammo); nd_read_short((short *)&new_ammo); if (rewrite) { nd_write_short(old_ammo); nd_write_short(new_ammo); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[Player_num].primary_ammo[Primary_weapon] = old_ammo; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[Player_num].primary_ammo[Primary_weapon] = new_ammo; break; } case ND_EVENT_SECONDARY_AMMO: { short old_ammo, new_ammo; nd_read_short(&old_ammo); nd_read_short(&new_ammo); if (rewrite) { nd_write_short(old_ammo); nd_write_short(new_ammo); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) Players[Player_num].secondary_ammo[Secondary_weapon] = old_ammo; else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) Players[Player_num].secondary_ammo[Secondary_weapon] = new_ammo; break; } case ND_EVENT_DOOR_OPENING: { short segnum; sbyte side; nd_read_short(&segnum); nd_read_byte(&side); if (rewrite) { nd_write_short(segnum); nd_write_byte(side); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { int anim_num; int cside; segment *segp, *csegp; segp = &Segments[segnum]; csegp = &Segments[segp->children[side]]; cside = find_connect_side(segp, csegp); anim_num = Walls[segp->sides[side].wall_num].clip_num; if (WallAnims[anim_num].flags & WCF_TMAP1) { segp->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[0]; } else { segp->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[0]; } } break; } case ND_EVENT_LASER_LEVEL: { sbyte old_level, new_level; nd_read_byte(&old_level); nd_read_byte(&new_level); if (rewrite) { nd_write_byte(old_level); nd_write_byte(new_level); break; } if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { Players[Player_num].laser_level = old_level; update_laser_weapon_info(); } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) { Players[Player_num].laser_level = new_level; update_laser_weapon_info(); } break; } case ND_EVENT_NEW_LEVEL: { sbyte new_level, old_level, loaded_level; nd_read_byte (&new_level); nd_read_byte (&old_level); if (rewrite) { nd_write_byte (new_level); nd_write_byte (old_level); break; } if (Newdemo_vcr_state == ND_STATE_PAUSED) break; stop_time(); if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) loaded_level = old_level; else { loaded_level = new_level; for (i = 0; i < MAX_PLAYERS; i++) { Players[i].cloak_time = 0; Players[i].flags &= ~PLAYER_FLAGS_CLOAKED; } } #ifdef DEST_SAT if ( (loaded_level < Last_secret_level) || (loaded_level > Last_level - 1) ) { nm_messagebox( NULL, 1, TXT_OK, TXT_NO_DESTSAT_LVL ); free_mission(); return -1; } #else if ((loaded_level < Last_secret_level) || (loaded_level > Last_level)) { nm_messagebox( NULL, 1, TXT_OK, "%s\n%s\n%s", TXT_CANT_PLAYBACK, TXT_LEVEL_CANT_LOAD, TXT_DEMO_OLD_CORRUPT ); free_mission(); return -1; } #endif LoadLevel((int)loaded_level,1); nd_playback_v_cntrlcen_destroyed = 0; reset_palette_add(); // get palette back to normal palette_save(); // initialise for palette_restore() start_time(); break; } case ND_EVENT_EOF: { done=-1; PHYSFS_seek(infile, PHYSFS_tell(infile) - 1); // get back to the EOF marker nd_playback_v_at_eof = 1; nd_playback_v_framecount++; break; } default: Int3(); } } // Now set up cockpit and views according to what we read out. Note that the demo itself cannot determinate the right views since it does not use a good portion of the real game code. if (nd_playback_v_dead) { Rear_view = 0; if (PlayerCfg.CockpitMode[1] != CM_LETTERBOX) select_cockpit(CM_LETTERBOX); } else if (nd_playback_v_rear) { Rear_view = nd_playback_v_rear; if (PlayerCfg.CockpitMode[0] == CM_FULL_COCKPIT) select_cockpit(CM_REAR_VIEW); } else { Rear_view = 0; if (PlayerCfg.CockpitMode[1] != PlayerCfg.CockpitMode[0]) select_cockpit(PlayerCfg.CockpitMode[0]); } if (nd_playback_v_bad_read) { nm_messagebox( NULL, 1, TXT_OK, "%s %s", TXT_DEMO_ERR_READING, TXT_DEMO_OLD_CORRUPT ); free_mission(); } return done; } void newdemo_goto_beginning() { //if (nd_playback_v_framecount == 0) // return; PHYSFS_seek(infile, 0); Newdemo_vcr_state = ND_STATE_PLAYBACK; if (newdemo_read_demo_start(0)) newdemo_stop_playback(); if (newdemo_read_frame_information(0) == -1) newdemo_stop_playback(); if (newdemo_read_frame_information(0) == -1) newdemo_stop_playback(); Newdemo_vcr_state = ND_STATE_PAUSED; nd_playback_v_at_eof = 0; } void newdemo_goto_end(int to_rewrite) { short frame_length=0, byte_count=0, bshort=0; sbyte level=0, bbyte=0, laser_level=0, c=0, cloaked=0; ubyte energy=0, shield=0; int i=0, loc=0, bint=0; PHYSFSX_fseek(infile, -2, SEEK_END); nd_read_byte(&level); if (!to_rewrite) { if ((level < Last_secret_level) || (level > Last_level)) { nm_messagebox( NULL, 1, TXT_OK, "%s\n%s\n%s", TXT_CANT_PLAYBACK, TXT_LEVEL_CANT_LOAD, TXT_DEMO_OLD_CORRUPT ); free_mission(); newdemo_stop_playback(); return; } if (level != Current_level_num) { LoadLevel(level,1); } } else Current_level_num = level; if (shareware) { if (Newdemo_game_mode & GM_MULTI) { PHYSFSX_fseek(infile, -10, SEEK_END); nd_read_byte(&cloaked); for (i = 0; i < MAX_PLAYERS; i++) { if ((1 << i) & cloaked) Players[i].flags |= PLAYER_FLAGS_CLOAKED; Players[i].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } } if (to_rewrite) return; PHYSFSX_fseek(infile, -12, SEEK_END); nd_read_short(&frame_length); } else { PHYSFSX_fseek(infile, -4, SEEK_END); nd_read_short(&byte_count); PHYSFSX_fseek(infile, -2 - byte_count, SEEK_CUR); nd_read_short(&frame_length); loc = PHYSFS_tell(infile); if (Newdemo_game_mode & GM_MULTI) { nd_read_byte(&cloaked); for (i = 0; i < MAX_PLAYERS; i++) if (cloaked & (1 << i)) Players[i].flags |= PLAYER_FLAGS_CLOAKED; } else nd_read_byte(&bbyte); nd_read_byte(&bbyte); nd_read_short(&bshort); nd_read_int(&bint); nd_read_byte((sbyte *)&energy); nd_read_byte((sbyte *)&shield); Players[Player_num].energy = i2f(energy); Players[Player_num].shields = i2f(shield); nd_read_int((int *)&(Players[Player_num].flags)); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { Players[Player_num].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); } if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) Players[Player_num].invulnerable_time = GameTime64 - (INVULNERABLE_TIME_MAX / 2); nd_read_byte((sbyte *)&Primary_weapon); nd_read_byte((sbyte *)&Secondary_weapon); for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) nd_read_short((short *)&(Players[Player_num].primary_ammo[i])); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) nd_read_short((short *)&(Players[Player_num].secondary_ammo[i])); nd_read_byte(&laser_level); if (laser_level != Players[Player_num].laser_level) { Players[Player_num].laser_level = laser_level; if (!to_rewrite) update_laser_weapon_info(); } if (Newdemo_game_mode & GM_MULTI) { nd_read_byte(&c); N_players = (int)c; // see newdemo_read_start_demo for explanation of // why this is commented out // nd_read_byte((sbyte *)&N_players); for (i = 0; i < N_players; i++) { nd_read_string(Players[i].callsign); nd_read_byte(&(Players[i].connected)); if (Newdemo_game_mode & GM_MULTI_COOP) { nd_read_int(&(Players[i].score)); } else { nd_read_short((short *)&(Players[i].net_killed_total)); nd_read_short((short *)&(Players[i].net_kills_total)); } } } else { nd_read_int(&(Players[Player_num].score)); } if (to_rewrite) return; PHYSFSX_fseek(infile, loc, SEEK_SET); } PHYSFSX_fseek(infile, -frame_length, SEEK_CUR); nd_read_int(&nd_playback_v_framecount); // get the frame count nd_playback_v_framecount--; PHYSFSX_fseek(infile, 4, SEEK_CUR); Newdemo_vcr_state = ND_STATE_PLAYBACK; newdemo_read_frame_information(0); // then the frame information Newdemo_vcr_state = ND_STATE_PAUSED; return; } void newdemo_back_frames(int frames) { short last_frame_length; int i; for (i = 0; i < frames; i++) { PHYSFS_seek(infile, PHYSFS_tell(infile) - 10); nd_read_short(&last_frame_length); PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length); if (!nd_playback_v_at_eof && newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); return; } if (nd_playback_v_at_eof) nd_playback_v_at_eof = 0; PHYSFS_seek(infile, PHYSFS_tell(infile) - 10); nd_read_short(&last_frame_length); PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length); } } /* * routine to interpolate the viewer position. the current position is * stored in the Viewer object. Save this position, and read the next * frame to get all objects read in. Calculate the delta playback and * the delta recording frame times between the two frames, then intepolate * the viewers position accordingly. nd_recorded_time is the time that it * took the recording to render the frame that we are currently looking * at. */ void interpolate_frame(fix d_play, fix d_recorded) { int i, j, num_cur_objs; fix factor; object *cur_objs; static fix InterpolStep = fl2f(.01); if (nd_playback_v_framecount < 1) return; factor = fixdiv(d_play, d_recorded); if (factor > F1_0) factor = F1_0; num_cur_objs = Highest_object_index; cur_objs = (object *)d_malloc(sizeof(object) * (num_cur_objs + 1)); if (cur_objs == NULL) { Int3(); return; } for (i = 0; i <= num_cur_objs; i++) memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object)); Newdemo_vcr_state = ND_STATE_PAUSED; if (newdemo_read_frame_information(0) == -1) { d_free(cur_objs); newdemo_stop_playback(); return; } InterpolStep -= FrameTime; // This interpolating looks just more crappy on high FPS, so let's not even waste performance on it. if (InterpolStep <= 0) { for (i = 0; i <= num_cur_objs; i++) { for (j = 0; j <= Highest_object_index; j++) { if (cur_objs[i].signature == Objects[j].signature) { sbyte render_type = cur_objs[i].render_type; fix delta_x, delta_y, delta_z; // Extract the angles from the object orientation matrix. // Some of this code taken from ai_turn_towards_vector // Don't do the interpolation on certain render types which don't use an orientation matrix if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) { vms_vector fvec1, fvec2, rvec1, rvec2; fix mag1; fvec1 = cur_objs[i].orient.fvec; vm_vec_scale(&fvec1, F1_0-factor); fvec2 = Objects[j].orient.fvec; vm_vec_scale(&fvec2, factor); vm_vec_add2(&fvec1, &fvec2); mag1 = vm_vec_normalize_quick(&fvec1); if (mag1 > F1_0/256) { rvec1 = cur_objs[i].orient.rvec; vm_vec_scale(&rvec1, F1_0-factor); rvec2 = Objects[j].orient.rvec; vm_vec_scale(&rvec2, factor); vm_vec_add2(&rvec1, &rvec2); vm_vec_normalize_quick(&rvec1); // Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1 vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1); } } // Interpolate the object position. This is just straight linear // interpolation. delta_x = Objects[j].pos.x - cur_objs[i].pos.x; delta_y = Objects[j].pos.y - cur_objs[i].pos.y; delta_z = Objects[j].pos.z - cur_objs[i].pos.z; delta_x = fixmul(delta_x, factor); delta_y = fixmul(delta_y, factor); delta_z = fixmul(delta_z, factor); cur_objs[i].pos.x += delta_x; cur_objs[i].pos.y += delta_y; cur_objs[i].pos.z += delta_z; } } } InterpolStep = fl2f(.01); } // get back to original position in the demo file. Reread the current // frame information again to reset all of the object stuff not covered // with Highest_object_index and the object array (previously rendered // objects, etc....) newdemo_back_frames(1); newdemo_back_frames(1); if (newdemo_read_frame_information(0) == -1) newdemo_stop_playback(); Newdemo_vcr_state = ND_STATE_PLAYBACK; for (i = 0; i <= num_cur_objs; i++) memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object)); Highest_object_index = num_cur_objs; d_free(cur_objs); } void newdemo_playback_one_frame() { int frames_back, i, level; static fix base_interpol_time = 0; static fix d_recorded = 0; for (i = 0; i < MAX_PLAYERS; i++) if (Players[i].flags & PLAYER_FLAGS_CLOAKED) Players[i].cloak_time = GameTime64 - (CLOAK_TIME_MAX / 2); if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) Players[Player_num].invulnerable_time = GameTime64 - (INVULNERABLE_TIME_MAX / 2); if (Newdemo_vcr_state == ND_STATE_PAUSED) // render a frame or not return; Control_center_destroyed = 0; Countdown_seconds_left = -1; PALETTE_FLASH_SET(0,0,0); //clear flash if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) { level = Current_level_num; if (nd_playback_v_framecount == 0) return; else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (nd_playback_v_framecount < 10)) { newdemo_goto_beginning(); return; } if (Newdemo_vcr_state == ND_STATE_REWINDING) frames_back = 10; else frames_back = 1; if (nd_playback_v_at_eof) { PHYSFS_seek(infile, PHYSFS_tell(infile) + (shareware ? -2 : +11)); } newdemo_back_frames(frames_back); if (level != Current_level_num) newdemo_pop_ctrlcen_triggers(); if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) { if (level != Current_level_num) newdemo_back_frames(1); Newdemo_vcr_state = ND_STATE_PAUSED; } } else if (Newdemo_vcr_state == ND_STATE_FASTFORWARD) { if (!nd_playback_v_at_eof) { for (i = 0; i < 10; i++) { if (newdemo_read_frame_information(0) == -1) { if (nd_playback_v_at_eof) Newdemo_vcr_state = ND_STATE_PAUSED; else newdemo_stop_playback(); break; } } } else Newdemo_vcr_state = ND_STATE_PAUSED; } else if (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD) { if (!nd_playback_v_at_eof) { level = Current_level_num; if (newdemo_read_frame_information(0) == -1) { if (!nd_playback_v_at_eof) newdemo_stop_playback(); } if (level != Current_level_num) { if (newdemo_read_frame_information(0) == -1) { if (!nd_playback_v_at_eof) newdemo_stop_playback(); } } Newdemo_vcr_state = ND_STATE_PAUSED; } else Newdemo_vcr_state = ND_STATE_PAUSED; } else { // First, uptate the total playback time to date. Then we check to see // if we need to change the playback style to interpolate frames or // skip frames based on where the playback time is relative to the // recorded time. if (nd_playback_v_framecount <= 0) nd_playback_total = nd_recorded_total; // baseline total playback time else nd_playback_total += FrameTime; if (nd_playback_v_style == NORMAL_PLAYBACK) { if (nd_playback_total > nd_recorded_total) nd_playback_v_style = SKIP_PLAYBACK; if (nd_recorded_total > 0 && nd_recorded_time > 0) { nd_playback_v_style = INTERPOLATE_PLAYBACK; nd_playback_total = nd_recorded_total + FrameTime; // baseline playback time base_interpol_time = nd_recorded_total; d_recorded = nd_recorded_time; // baseline delta recorded } } if ((nd_playback_v_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) { fix d_play = 0; if (nd_recorded_total - nd_playback_total < FrameTime) { d_recorded = nd_recorded_total - nd_playback_total; while (nd_recorded_total - nd_playback_total < FrameTime) { object *cur_objs; int i, j, num_objs, level; num_objs = Highest_object_index; cur_objs = (object *)d_malloc(sizeof(object) * (num_objs + 1)); if (cur_objs == NULL) { Warning ("Couldn't get %lu bytes for objects in interpolate playback\n", sizeof(object) * num_objs); break; } for (i = 0; i <= num_objs; i++) memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object)); level = Current_level_num; if (newdemo_read_frame_information(0) == -1) { d_free(cur_objs); newdemo_stop_playback(); return; } if (level != Current_level_num) { d_free(cur_objs); if (newdemo_read_frame_information(0) == -1) newdemo_stop_playback(); break; } // for each new object in the frame just read in, determine if there is // a corresponding object that we have been interpolating. If so, then // copy that interpolated object to the new Objects array so that the // interpolated position and orientation can be preserved. for (i = 0; i <= num_objs; i++) { for (j = 0; j <= Highest_object_index; j++) { if (cur_objs[i].signature == Objects[j].signature) { memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix)); memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector)); break; } } } d_free(cur_objs); d_recorded += nd_recorded_time; base_interpol_time = nd_playback_total - FrameTime; } } d_play = nd_playback_total - base_interpol_time; interpolate_frame(d_play, d_recorded); return; } else { if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); return; } if (nd_playback_v_style == SKIP_PLAYBACK) { while (nd_playback_total > nd_recorded_total) { if (newdemo_read_frame_information(0) == -1) { newdemo_stop_playback(); return; } } } } } } void newdemo_start_recording() { Newdemo_num_written = 0; nd_record_v_no_space=0; Newdemo_state = ND_STATE_RECORDING; PHYSFS_mkdir(DEMO_DIR); //always try making directory - could only exist in read-only path outfile = PHYSFSX_openWriteBuffered(DEMO_FILENAME); if (outfile == NULL) { Newdemo_state = ND_STATE_NORMAL; nm_messagebox(NULL, 1, TXT_OK, "Cannot open demo temp file"); } else newdemo_record_start_demo(); } void newdemo_write_end() { sbyte cloaked = 0; unsigned short byte_count = 0; int i; nd_write_byte(ND_EVENT_EOF); nd_write_short(nd_record_v_framebytes_written - 1); if (Game_mode & GM_MULTI) { for (i = 0; i < N_players; i++) { if (Players[i].flags & PLAYER_FLAGS_CLOAKED) cloaked |= (1 << i); } nd_write_byte(cloaked); nd_write_byte(ND_EVENT_EOF); } else { nd_write_short(ND_EVENT_EOF); } nd_write_short(ND_EVENT_EOF); nd_write_int(ND_EVENT_EOF); if (!shareware) { byte_count += 10; // from nd_record_v_framebytes_written nd_write_byte((sbyte)(f2ir(Players[Player_num].energy))); nd_write_byte((sbyte)(f2ir(Players[Player_num].shields))); nd_write_int(Players[Player_num].flags); // be sure players flags are set nd_write_byte((sbyte)Primary_weapon); nd_write_byte((sbyte)Secondary_weapon); byte_count += 8; for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) nd_write_short((short)Players[Player_num].primary_ammo[i]); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) nd_write_short((short)Players[Player_num].secondary_ammo[i]); byte_count += (sizeof(short) * (MAX_PRIMARY_WEAPONS + MAX_SECONDARY_WEAPONS)); nd_write_byte(Players[Player_num].laser_level); byte_count++; if (Game_mode & GM_MULTI) { nd_write_byte((sbyte)N_players); byte_count++; for (i = 0; i < N_players; i++) { nd_write_string(Players[i].callsign); byte_count += (strlen(Players[i].callsign) + 2); nd_write_byte(Players[i].connected); if (Game_mode & GM_MULTI_COOP) { nd_write_int(Players[i].score); byte_count += 5; } else { nd_write_short((short)Players[i].net_killed_total); nd_write_short((short)Players[i].net_kills_total); byte_count += 5; } } } else { nd_write_int(Players[Player_num].score); byte_count += 4; } nd_write_short(byte_count); } nd_write_byte(Current_level_num); nd_write_byte(ND_EVENT_EOF); } char demoname_allowed_chars[] = "azAZ09__--"; void newdemo_stop_recording() { newmenu_item m[6]; int exit; static char filename[PATH_MAX] = "", *s; static sbyte tmpcnt = 0; char fullname[PATH_MAX] = DEMO_DIR; exit = 0; if (!nd_record_v_no_space) { newdemo_record_oneframeevent_update(0); newdemo_write_end(); } PHYSFS_close(outfile); outfile = NULL; Newdemo_state = ND_STATE_NORMAL; gr_palette_load( gr_palette ); if (filename[0] != '\0') { int num, i = strlen(filename) - 1; char newfile[PATH_MAX]; while (isdigit(filename[i])) { i--; if (i == -1) break; } i++; num = atoi(&(filename[i])); num++; filename[i] = '\0'; sprintf (newfile, "%s%d", filename, num); strncpy(filename, newfile, PATH_MAX); filename[PATH_MAX - 1] = '\0'; } try_again: ; Newmenu_allowed_chars = demoname_allowed_chars; if (!nd_record_v_no_space) { m[0].type=NM_TYPE_INPUT; m[0].text_len = PATH_MAX - 1; m[0].text = filename; exit = newmenu_do( NULL, TXT_SAVE_DEMO_AS, 1, &(m[0]), NULL, NULL ); } else if (nd_record_v_no_space == 2) { m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_NOSPACE; m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = PATH_MAX - 1; m[1].text = filename; exit = newmenu_do( NULL, NULL, 2, m, NULL, NULL ); } Newmenu_allowed_chars = NULL; if (exit == -2) { // got bumped out from network menu char save_file[PATH_MAX]; if (filename[0] != '\0') { strcpy(save_file, DEMO_DIR); strcat(save_file, filename); strcat(save_file, DEMO_EXT); } else sprintf (save_file, "%stmp%d.dem", DEMO_DIR, tmpcnt++); remove(save_file); PHYSFSX_rename(DEMO_FILENAME, save_file); return; } if (exit == -1) { // pressed ESC PHYSFS_delete(DEMO_FILENAME); // might as well remove the file return; // return without doing anything } if (filename[0]==0) //null string goto try_again; //check to make sure name is ok for (s=filename;*s;s++) if (!isalnum(*s) && *s!='_') { nm_messagebox(NULL, 1,TXT_CONTINUE, TXT_DEMO_USE_LETTERS); goto try_again; } if (nd_record_v_no_space) strcat(fullname, m[1].text); else strcat(fullname, m[0].text); strcat(fullname, DEMO_EXT); PHYSFS_delete(fullname); PHYSFSX_rename(DEMO_FILENAME, fullname); } //returns the number of demo files on the disk int newdemo_count_demos() { char **find, **i; static const char *const types[] = { DEMO_EXT, NULL }; int NumFiles=0; find = PHYSFSX_findFiles(DEMO_DIR, types); for (i = find; *i != NULL; i++) NumFiles++; PHYSFS_freeList(find); return NumFiles; } void newdemo_start_playback(char * filename) { char **find = NULL, **i; int rnd_demo = 0; char filename2[PATH_MAX+FILENAME_LEN] = DEMO_DIR; #ifdef NETWORK change_playernum_to(0); #endif if (filename) strcat(filename2, filename); else { // Randomly pick a filename int NumFiles = 0, RandFileNum; static const char *const types[] = { DEMO_EXT, NULL }; rnd_demo = 1; NumFiles = newdemo_count_demos(); if ( NumFiles == 0 ) { GameArg.SysAutoDemo = 0; return; // No files found! } RandFileNum = d_rand() % NumFiles; NumFiles = 0; find = PHYSFSX_findFiles(DEMO_DIR, types); for (i = find; *i != NULL; i++) { if (NumFiles == RandFileNum) { strcat(filename2, *i); break; } NumFiles++; } PHYSFS_freeList(find); if (NumFiles > RandFileNum) { GameArg.SysAutoDemo = 0; return; } } infile = PHYSFSX_openReadBuffered(filename2); if (infile==NULL) { return; } nd_playback_v_bad_read = 0; #ifdef NETWORK change_playernum_to(0); // force playernum to 0 #endif strncpy(nd_playback_v_save_callsign, Players[Player_num].callsign, CALLSIGN_LEN); Players[Player_num].lives=0; Viewer = ConsoleObject = &Objects[0]; // play properly as if console player if (newdemo_read_demo_start(rnd_demo)) { PHYSFS_close(infile); return; } Game_mode = GM_NORMAL; Newdemo_state = ND_STATE_PLAYBACK; Newdemo_vcr_state = ND_STATE_PLAYBACK; nd_playback_v_demosize = PHYSFS_fileLength(infile); nd_playback_v_bad_read = 0; nd_playback_v_at_eof = 0; nd_playback_v_framecount = 0; nd_playback_v_style = NORMAL_PLAYBACK; nd_playback_v_dead = nd_playback_v_rear = 0; HUD_clear_messages(); if (!Game_wind) hide_menus(); newdemo_playback_one_frame(); // this one loads new level newdemo_playback_one_frame(); // get all of the objects to renderb game if (!Game_wind) Game_wind = game_setup(); // create game environment } void newdemo_stop_playback() { PHYSFS_close(infile); Newdemo_state = ND_STATE_NORMAL; #ifdef NETWORK change_playernum_to(0); //this is reality #endif strncpy(Players[Player_num].callsign, nd_playback_v_save_callsign, CALLSIGN_LEN); Rear_view=0; nd_playback_v_dead = nd_playback_v_rear = 0; Newdemo_game_mode = Game_mode = GM_GAME_OVER; // Required for the editor obj_relink_all(); if (Game_wind) window_close(Game_wind); // Exit game loop } int newdemo_swap_endian(char *filename) { char inpath[PATH_MAX+FILENAME_LEN] = DEMO_DIR; int complete = 0; if (filename) strcat(inpath, filename); else return 0; infile = PHYSFSX_openReadBuffered(inpath); if (infile==NULL) goto read_error; nd_playback_v_demosize = PHYSFS_fileLength(infile); // should be exactly the same size outfile = PHYSFSX_openWriteBuffered(DEMO_FILENAME); if (outfile==NULL) { PHYSFS_close(infile); goto read_error; } Newdemo_num_written = 0; nd_playback_v_bad_read = 0; swap_endian = 1; nd_playback_v_at_eof = 0; Newdemo_state = ND_STATE_NORMAL; // not doing anything special really if (newdemo_read_demo_start(PURPOSE_REWRITE)) { PHYSFS_close(infile); PHYSFS_close(outfile); swap_endian = 0; return 0; } while (newdemo_read_frame_information(1) == 1) {} // rewrite all frames newdemo_goto_end(1); // get end of demo data newdemo_write_end(); // and write it swap_endian = 0; complete = nd_playback_v_demosize == Newdemo_num_written; PHYSFS_close(infile); PHYSFS_close(outfile); outfile = NULL; if (complete) { char bakpath[PATH_MAX+FILENAME_LEN]; change_filename_extension(bakpath, inpath, DEMO_BACKUP_EXT); PHYSFSX_rename(inpath, bakpath); PHYSFSX_rename(DEMO_FILENAME, inpath); } else PHYSFS_delete(DEMO_FILENAME); // clean up the mess read_error: { nm_messagebox( NULL, 1, TXT_OK, complete ? "Demo %s converted%s" : "Error converting demo\n%s\n%s", filename, complete ? "" : (nd_playback_v_at_eof ? TXT_DEMO_CORRUPT : PHYSFS_getLastError())); } return nd_playback_v_at_eof; } #ifndef NDEBUG #define BUF_SIZE 16384 void newdemo_strip_frames(char *outname, int bytes_to_strip) { PHYSFS_file *outfile; char *buf; int read_elems, bytes_back; int trailer_start, loc1, loc2, stop_loc, bytes_to_read; short last_frame_length; outfile = PHYSFSX_openWriteBuffered(outname); if (outfile == NULL) { nm_messagebox( NULL, 1, TXT_OK, "Can't open output file" ); newdemo_stop_playback(); return; } buf = d_malloc(BUF_SIZE); if (buf == NULL) { nm_messagebox( NULL, 1, TXT_OK, "Can't malloc output buffer" ); PHYSFS_close(outfile); newdemo_stop_playback(); return; } newdemo_goto_end(0); trailer_start = PHYSFS_tell(infile); PHYSFS_seek(infile, PHYSFS_tell(infile) + 11); bytes_back = 0; while (bytes_back < bytes_to_strip) { loc1 = PHYSFS_tell(infile); newdemo_back_frames(1); loc2 = PHYSFS_tell(infile); bytes_back += (loc1 - loc2); } PHYSFS_seek(infile, PHYSFS_tell(infile) - 10); nd_read_short(&last_frame_length); PHYSFS_seek(infile, PHYSFS_tell(infile) - 3); stop_loc = PHYSFS_tell(infile); PHYSFS_seek(infile, 0); while (stop_loc > 0) { if (stop_loc < BUF_SIZE) bytes_to_read = stop_loc; else bytes_to_read = BUF_SIZE; read_elems = PHYSFS_read(infile, buf, 1, bytes_to_read); PHYSFS_write(outfile, buf, 1, read_elems); stop_loc -= read_elems; } stop_loc = PHYSFS_tell(outfile); PHYSFS_seek(infile, trailer_start); while ((read_elems = PHYSFS_read(infile, buf, 1, BUF_SIZE)) != 0) PHYSFS_write(outfile, buf, 1, read_elems); PHYSFS_seek(outfile, stop_loc); PHYSFS_seek(outfile, PHYSFS_tell(infile) + 1); PHYSFS_write(outfile, &last_frame_length, 2, 1); PHYSFS_close(outfile); newdemo_stop_playback(); } #endif dxx-rebirth-0.58.1-d1x/main/newdemo.h000066400000000000000000000113411217717257200173050ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * header for demo playback system * */ #ifndef _NEWDEMO_H #define _NEWDEMO_H #define ND_STATE_NORMAL 0 #define ND_STATE_RECORDING 1 #define ND_STATE_PLAYBACK 2 #define ND_STATE_PAUSED 3 #define ND_STATE_REWINDING 4 #define ND_STATE_FASTFORWARD 5 #define ND_STATE_ONEFRAMEFORWARD 6 #define ND_STATE_ONEFRAMEBACKWARD 7 #define DEMO_DIR "demos/" #define DEMO_EXT ".dem" #ifdef WORDS_BIGENDIAN #define DEMO_BACKUP_EXT "386" #else #define DEMO_BACKUP_EXT "ppc" #endif // Gives state of recorder extern int Newdemo_state; extern int NewdemoFrameCount; extern int Newdemo_vcr_state; extern int Newdemo_game_mode; extern sbyte Newdemo_do_interpolate; extern int Newdemo_show_percentage; // Functions called during recording process... extern void newdemo_record_start_demo(); extern void newdemo_record_start_frame(fix frame_time ); extern void newdemo_record_render_object(object * obj); extern void newdemo_record_viewer_object(object * obj); extern void newdemo_record_sound_3d( int soundno, int angle, int volume ); extern void newdemo_record_sound_3d_once( int soundno, int angle, int volume ); extern void newdemo_record_sound_once( int soundno ); extern void newdemo_record_sound( int soundno ); extern void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum ); extern void newdemo_record_hostage_rescued( int hostage_num ); extern void newdemo_record_morph_frame(); extern void newdemo_record_player_stats(int shields, int energy, int score ); extern void newdemo_record_wall_toggle(int segnum, int side ); extern void newdemo_record_control_center_destroyed(); extern void newdemo_record_hud_message(const char *s); extern void newdemo_record_palette_effect(short r, short g, short b); extern void newdemo_record_player_energy(int); extern void newdemo_record_player_shields(int); extern void newdemo_record_player_flags(uint); extern void newdemo_record_player_weapon(int, int); extern void newdemo_record_effect_blowup(short, int, vms_vector *); extern void newdemo_record_homing_distance(fix); extern void newdemo_record_letterbox(void); extern void newdemo_record_rearview(void); extern void newdemo_record_restore_cockpit(void); extern void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap); extern void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap); extern void newdemo_record_multi_cloak(int pnum); extern void newdemo_record_multi_decloak(int pnum); extern void newdemo_set_new_level(int level_num); extern void newdemo_record_restore_rearview(void); extern void newdemo_record_multi_death(int pnum); extern void newdemo_record_multi_kill(int pnum, sbyte kill); extern void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign); extern void newdemo_record_multi_reconnect(int pnum); extern void newdemo_record_multi_disconnect(int pnum); extern void newdemo_record_player_score(int score); extern void newdemo_record_multi_score(int pnum, int score); extern void newdemo_record_primary_ammo(int new_ammo); extern void newdemo_record_secondary_ammo(int new_ammo); extern void newdemo_record_door_opening(int segnum, int side); extern void newdemo_record_laser_level(sbyte old_level, sbyte new_level); // Functions called during playback process... extern void newdemo_object_move_all(); extern void newdemo_playback_one_frame(); extern void newdemo_goto_end(int to_rewrite); extern void newdemo_goto_beginning(); // Interactive functions to control playback/record; extern void newdemo_start_playback( char * filename ); extern void newdemo_stop_playback(); extern void newdemo_start_recording(); extern void newdemo_stop_recording(); extern int newdemo_swap_endian(char *filename); extern int newdemo_get_percent_done(); extern void newdemo_record_link_sound_to_object3( int soundno, short objnum, fix max_volume, fix max_distance, int loop_start, int loop_end ); extern int newdemo_find_object( int signature ); extern void newdemo_record_kill_sound_linked_to_object( int objnum ); #endif // _NEWDEMO_H dxx-rebirth-0.58.1-d1x/main/newmenu.c000066400000000000000000001635061217717257200173330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for menus. * */ #include #include #include #include #include #include "pstypes.h" #include "dxxerror.h" #include "gr.h" #include "grdef.h" #include "window.h" #include "songs.h" #include "key.h" #include "mouse.h" #include "palette.h" #include "game.h" #include "text.h" #include "menu.h" #include "newmenu.h" #include "gamefont.h" #include "iff.h" #include "pcx.h" #include "u_mem.h" #include "mouse.h" #include "joy.h" #include "digi.h" #include "multi.h" #include "endlevel.h" #include "screens.h" #include "config.h" #include "player.h" #include "state.h" #include "newdemo.h" #include "kconfig.h" #include "strutil.h" #include "vers_id.h" #include "timer.h" #include "playsave.h" #include "automap.h" #include "rbaudio.h" #ifdef OGL #include "ogl_init.h" #endif #define MAXDISPLAYABLEITEMS 14 #define MAXDISPLAYABLEITEMSTINY 21 #define MESSAGEBOX_TEXT_SIZE 2176 // How many characters in messagebox #define MAX_TEXT_WIDTH FSPACX(120) // How many pixels wide a input box can be struct newmenu { window *wind; int x,y,w,h; short swidth, sheight; float fntscalex, fntscaley; // with these we check if resolution or fonts have changed so menu structure can be recreated char *title; char *subtitle; int nitems; newmenu_item *items; int (*subfunction)(newmenu *menu, d_event *event, void *userdata); int citem; char *filename; int tiny_mode; int tabs_flag; int reorderitems; int scroll_offset, last_scroll_check, max_displayable; int all_text; //set true if all text items int is_scroll_box; // Is this a scrolling box? Set to false at init int max_on_menu; int mouse_state, dblclick_flag; int *rval; // Pointer to return value (for polling newmenus) void *userdata; // For whatever - like with window system }; grs_bitmap nm_background, nm_background1; grs_bitmap *nm_background_sub = NULL; newmenu *newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem, char * filename, int TinyMode, int TabsFlag ); void newmenu_free_background() { if (nm_background.bm_data) { if (nm_background_sub) { gr_free_sub_bitmap(nm_background_sub); nm_background_sub = NULL; } gr_free_bitmap_data (&nm_background); } if (nm_background1.bm_data) gr_free_bitmap_data (&nm_background1); } // Draws the custom menu background pcx, if available void nm_draw_background1(char * filename) { int pcx_error; if (filename != NULL) { if (nm_background1.bm_data == NULL) { gr_init_bitmap_data (&nm_background1); pcx_error = pcx_read_bitmap( filename, &nm_background1, BM_LINEAR, gr_palette ); Assert(pcx_error == PCX_ERROR_NONE); (void)pcx_error; } gr_palette_load( gr_palette ); show_fullscr(&nm_background1); } } #define MENU_BACKGROUND_BITMAP_HIRES (PHYSFSX_exists("scoresb.pcx",1)?"scoresb.pcx":"scores.pcx") #define MENU_BACKGROUND_BITMAP_LORES (PHYSFSX_exists("scores.pcx",1)?"scores.pcx":"scoresb.pcx") #define MENU_BACKGROUND_BITMAP (HIRESMODE?MENU_BACKGROUND_BITMAP_HIRES:MENU_BACKGROUND_BITMAP_LORES) // Draws the frame background for menus void nm_draw_background(int x1, int y1, int x2, int y2 ) { int w,h,init_sub=0; static float BGScaleX=1,BGScaleY=1; grs_canvas *tmp,*old; if (nm_background.bm_data == NULL) { int pcx_error; ubyte background_palette[768]; gr_init_bitmap_data (&nm_background); pcx_error = pcx_read_bitmap(MENU_BACKGROUND_BITMAP,&nm_background,BM_LINEAR,background_palette); Assert(pcx_error == PCX_ERROR_NONE); (void)pcx_error; gr_remap_bitmap_good( &nm_background, background_palette, -1, -1 ); BGScaleX=((float)SWIDTH/nm_background.bm_w); BGScaleY=((float)SHEIGHT/nm_background.bm_h); init_sub=1; } if ( x1 < 0 ) x1 = 0; if ( y1 < 0 ) y1 = 0; if ( x2 > SWIDTH - 1) x2 = SWIDTH - 1; if ( y2 > SHEIGHT - 1) y2 = SHEIGHT - 1; w = x2-x1; h = y2-y1; if (w > SWIDTH) w = SWIDTH; if (h > SHEIGHT) h = SHEIGHT; old=grd_curcanv; tmp=gr_create_sub_canvas(old,x1,y1,w,h); gr_set_current_canvas(tmp); gr_palette_load( gr_palette ); show_fullscr( &nm_background ); // show so we load all necessary data for the sub-bitmap if (!init_sub && ((nm_background_sub->bm_w != w*(((float) nm_background.bm_w)/SWIDTH)) || (nm_background_sub->bm_h != h*(((float) nm_background.bm_h)/SHEIGHT)))) { init_sub=1; gr_free_sub_bitmap(nm_background_sub); nm_background_sub = NULL; } if (init_sub) nm_background_sub = gr_create_sub_bitmap(&nm_background,0,0,w*(((float) nm_background.bm_w)/SWIDTH),h*(((float) nm_background.bm_h)/SHEIGHT)); show_fullscr( nm_background_sub ); gr_set_current_canvas(old); gr_free_sub_canvas(tmp); gr_settransblend(14, GR_BLEND_NORMAL); gr_setcolor( BM_XRGB(1,1,1) ); for (w=5*BGScaleX;w>0;w--) gr_urect( x2-w, y1+w*(BGScaleY/BGScaleX), x2-w, y2-w*(BGScaleY/BGScaleX) );//right edge gr_setcolor( BM_XRGB(0,0,0) ); for (h=5*BGScaleY;h>0;h--) gr_urect( x1+h*(BGScaleX/BGScaleY), y2-h, x2-h*(BGScaleX/BGScaleY), y2-h );//bottom edge gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } // Draw a left justfied string void nm_string( int w1,int x, int y, char * s, int tabs_flag) { int w,h,aw,tx=0,t=0,i; char *p,*s1,*s2,measure[2]; int XTabs[]={18,90,127,165,231,256}; p=s1=NULL; s2 = d_strdup(s); for (i=0;i<6;i++) { XTabs[i]=FSPACX(XTabs[i]); XTabs[i]+=x; } measure[1]=0; if (!tabs_flag) { p = strchr( s2, '\t' ); if (p && (w1>0) ) { *p = '\0'; s1 = p+1; } } gr_get_string_size(s2, &w, &h, &aw ); if (w1 > 0) w = w1; if (tabs_flag) { for (i=0;i0) ) { gr_get_string_size(s1, &w, &h, &aw ); gr_string( x+w1-w, y, s1 ); *p = '\t'; } d_free(s2); } // Draw a slider and it's string void nm_string_slider( int w1,int x, int y, char * s ) { int w,h,aw; char *p,*s1; s1=NULL; p = strchr( s, '\t' ); if (p) { *p = '\0'; s1 = p+1; } gr_get_string_size(s, &w, &h, &aw ); gr_string( x, y, s ); if (p) { gr_get_string_size(s1, &w, &h, &aw ); gr_string( x+w1-w, y, s1 ); *p = '\t'; } } // Draw a left justfied string with black background. void nm_string_black( int w1,int x, int y, char * s ) { int w,h,aw; gr_get_string_size(s, &w, &h, &aw ); if (w1 == 0) w1 = w; gr_setcolor( BM_XRGB(5,5,5)); gr_rect( x - FSPACX(2), y-FSPACY(1), x+w1, y + h); gr_setcolor( BM_XRGB(2,2,2)); gr_rect( x - FSPACX(2), y - FSPACY(1), x, y + h ); gr_setcolor( BM_XRGB(0,0,0)); gr_rect( x - FSPACX(1), y - FSPACY(1), x+w1 - FSPACX(1), y + h); gr_string( x, y, s ); } // Draw a right justfied string void nm_rstring( int w1,int x, int y, char * s ) { int w,h,aw; gr_get_string_size(s, &w, &h, &aw ); x -= FSPACX(3); if (w1 == 0) w1 = w; gr_string( x-w, y, s ); } void nm_string_inputbox( int w, int x, int y, char * text, int current ) { int w1,h1,aw; // even with variable char widths and a box that goes over the whole screen, we maybe never get more than 75 chars on the line if (strlen(text)>75) text+=strlen(text)-75; while( *text ) { gr_get_string_size(text, &w1, &h1, &aw ); if ( w1 > w-FSPACX(10) ) text++; else break; } if ( *text == 0 ) w1 = 0; nm_string_black( w, x, y, text ); if ( current && timer_query() & 0x8000 ) gr_string( x+w1, y, CURSOR_STRING ); } void draw_item( newmenu_item *item, int is_current, int tiny, int tabs_flag, int scroll_offset ) { if (tiny) { if (is_current) gr_set_fontcolor(gr_find_closest_color_current(57,49,20),-1); else gr_set_fontcolor(gr_find_closest_color_current(29,29,47),-1); if (item->text[0]=='\t') gr_set_fontcolor (gr_find_closest_color_current(63,63,63),-1); } else { gr_set_curfont(is_current?MEDIUM2_FONT:MEDIUM1_FONT); } switch( item->type ) { case NM_TYPE_TEXT: case NM_TYPE_MENU: nm_string( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, tabs_flag ); break; case NM_TYPE_SLIDER: { int i,j; if (item->value < item->min_value) item->value=item->min_value; if (item->value > item->max_value) item->value=item->max_value; i = sprintf( item->saved_text, "%s\t%s", item->text, SLIDER_LEFT ); for (j=0; j<(item->max_value-item->min_value+1); j++ ) { i += sprintf( item->saved_text + i, "%s", SLIDER_MIDDLE ); } sprintf( item->saved_text + i, "%s", SLIDER_RIGHT ); item->saved_text[item->value+1+strlen(item->text)+1] = SLIDER_MARKER[0]; nm_string_slider( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->saved_text ); } break; case NM_TYPE_INPUT_MENU: if ( item->group==0 ) { nm_string( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, tabs_flag ); } else { nm_string_inputbox( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, is_current ); } break; case NM_TYPE_INPUT: nm_string_inputbox( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, is_current ); break; case NM_TYPE_CHECK: nm_string( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, tabs_flag ); if (item->value) nm_rstring( item->right_offset,item->x, item->y-(((int)LINE_SPACING)*scroll_offset), CHECKED_CHECK_BOX ); else nm_rstring( item->right_offset,item->x, item->y-(((int)LINE_SPACING)*scroll_offset), NORMAL_CHECK_BOX ); break; case NM_TYPE_RADIO: nm_string( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, tabs_flag ); if (item->value) nm_rstring( item->right_offset, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), CHECKED_RADIO_BOX ); else nm_rstring( item->right_offset, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), NORMAL_RADIO_BOX ); break; case NM_TYPE_NUMBER: { char text[10]; if (item->value < item->min_value) item->value=item->min_value; if (item->value > item->max_value) item->value=item->max_value; nm_string( item->w, item->x, item->y-(((int)LINE_SPACING)*scroll_offset), item->text, tabs_flag ); sprintf( text, "%d", item->value ); nm_rstring( item->right_offset,item->x, item->y-(((int)LINE_SPACING)*scroll_offset), text ); } break; } } const char *Newmenu_allowed_chars=NULL; //returns true if char is allowed int char_allowed(char c) { const char *p = Newmenu_allowed_chars; if (!p) return 1; while (*p) { Assert(p[1]); if (c>=p[0] && c<=p[1]) return 1; p += 2; } return 0; } void strip_end_whitespace( char * text ) { int i,l; l = strlen( text ); for (i=l-1; i>=0; i-- ) { if ( isspace(text[i]) ) text[i] = 0; else return; } } int newmenu_do( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata ) { return newmenu_do2( title, subtitle, nitems, item, subfunction, userdata, 0, NULL ); } newmenu *newmenu_dotiny( char * title, char * subtitle, int nitems, newmenu_item * item, int TabsFlag, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata ) { return newmenu_do4( title, subtitle, nitems, item, subfunction, userdata, 0, NULL, 1, TabsFlag ); } int newmenu_do1( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem ) { return newmenu_do2( title, subtitle, nitems, item, subfunction, userdata, citem, NULL ); } int newmenu_do2( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem, char * filename ) { newmenu *menu; window *wind; int rval = -1; menu = newmenu_do3( title, subtitle, nitems, item, subfunction, userdata, citem, filename ); if (!menu) return -1; menu->rval = &rval; wind = menu->wind; // avoid dereferencing a freed 'menu' // newmenu_do2 and simpler get their own event loop // This is so the caller doesn't have to provide a callback that responds to EVENT_NEWMENU_SELECTED while (window_exists(wind)) event_process(); return rval; } // Basically the same as do2 but sets reorderitems flag for weapon priority menu a bit redundant to get lose of a global variable but oh well... int newmenu_doreorder( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata ) { newmenu *menu; window *wind; int rval = -1; menu = newmenu_do3( title, subtitle, nitems, item, subfunction, userdata, 0, NULL ); if (!menu) return -1; menu->reorderitems = 1; menu->rval = &rval; wind = menu->wind; // avoid dereferencing a freed 'menu' // newmenu_do2 and simpler get their own event loop // This is so the caller doesn't have to provide a callback that responds to EVENT_NEWMENU_SELECTED while (window_exists(wind)) event_process(); return rval; } newmenu *newmenu_do3( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem, char * filename ) { return newmenu_do4( title, subtitle, nitems, item, subfunction, userdata, citem, filename, 0, 0 ); } newmenu *newmenu_do_fixedfont( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem, char * filename){ return newmenu_do4( title, subtitle, nitems, item, subfunction, userdata, citem, filename, 0, 0); } #ifdef NEWMENU_MOUSE ubyte Hack_DblClick_MenuMode=0; #endif newmenu_item *newmenu_get_items(newmenu *menu) { return menu->items; } int newmenu_get_nitems(newmenu *menu) { return menu->nitems; } int newmenu_get_citem(newmenu *menu) { return menu->citem; } window *newmenu_get_window(newmenu *menu) { return menu->wind; } void newmenu_scroll(newmenu *menu, int amount) { int i = 0, first = 0, last = 0; if (amount == 0) // nothing to do for us return; if (menu->all_text) { menu->scroll_offset += amount; if (menu->scroll_offset < 0) menu->scroll_offset = 0; if (menu->max_on_menu+menu->scroll_offset > menu->nitems) menu->scroll_offset = menu->nitems-menu->max_on_menu; return; } for (i = 0; i < menu->nitems; i++) // find first "usable" item { if (menu->items[i].type != NM_TYPE_TEXT) { first = i; break; } } for (i = menu->nitems-1; i >= first; i--) // find last "usable" item { if (menu->items[i].type != NM_TYPE_TEXT) { last = i; break; } } if (first == last) // nothing to do for us return; if (menu->citem == last && amount == 1) // if citem == last item and we want to go down one step, go to first item { newmenu_scroll(menu, -menu->nitems); return; } if (menu->citem == first && amount == -1) // if citem == first item and we want to go up one step, go to last item { newmenu_scroll(menu, menu->nitems); return; } i = 0; if (amount > 0) // down the list { do // count down until we reached a non NM_TYPE_TEXT item and reached our amount { if (menu->citem == last) // stop if we reached the last item return; i++; menu->citem++; if (menu->is_scroll_box) // update scroll_offset as we go down the menu { menu->last_scroll_check=-1; if (menu->citem+4>=menu->max_on_menu+menu->scroll_offset && menu->scroll_offset < menu->nitems-menu->max_on_menu) menu->scroll_offset++; } } while (menu->items[menu->citem].type == NM_TYPE_TEXT || i < amount); } else if (amount < 0) // up the list { do // count up until we reached a non NM_TYPE_TEXT item and reached our amount { if (menu->citem == first) // stop if we reached the first item return; i--; menu->citem--; if (menu->is_scroll_box) // update scroll_offset as we go up the menu { menu->last_scroll_check=-1; if (menu->citem-4scroll_offset && menu->scroll_offset > 0) menu->scroll_offset--; } } while (menu->items[menu->citem].type == NM_TYPE_TEXT || i > amount); } } int newmenu_mouse(window *wind, d_event *event, newmenu *menu, int button) { int old_choice, i, mx=0, my=0, mz=0, x1 = 0, x2, y1, y2, changed = 0; grs_canvas *menu_canvas = window_get_canvas(wind), *save_canvas = grd_curcanv; switch (button) { case MBTN_LEFT: { gr_set_current_canvas(menu_canvas); old_choice = menu->citem; if ((event->type == EVENT_MOUSE_BUTTON_DOWN) && !menu->all_text) { mouse_get_pos(&mx, &my, &mz); for (i=menu->scroll_offset; imax_on_menu+menu->scroll_offset; i++ ) { x1 = grd_curcanv->cv_bitmap.bm_x + menu->items[i].x-FSPACX(13) /*- menu->items[i].right_offset - 6*/; x2 = x1 + menu->items[i].w+FSPACX(13); y1 = grd_curcanv->cv_bitmap.bm_y + menu->items[i].y - (((int)LINE_SPACING)*menu->scroll_offset); y2 = y1 + menu->items[i].h; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) { if (i != menu->citem) { if(Hack_DblClick_MenuMode) menu->dblclick_flag = 0; } menu->citem = i; switch( menu->items[menu->citem].type ) { case NM_TYPE_CHECK: if ( menu->items[menu->citem].value ) menu->items[menu->citem].value = 0; else menu->items[menu->citem].value = 1; if (menu->is_scroll_box) menu->last_scroll_check=-1; changed = 1; break; case NM_TYPE_RADIO: for (i=0; initems; i++ ) { if ((i!=menu->citem) && (menu->items[i].type==NM_TYPE_RADIO) && (menu->items[i].group==menu->items[menu->citem].group) && (menu->items[i].value) ) { menu->items[i].value = 0; changed = 1; } } menu->items[menu->citem].value = 1; break; case NM_TYPE_TEXT: menu->citem=old_choice; menu->mouse_state=0; break; } break; } } } if ( menu->mouse_state ) { mouse_get_pos(&mx, &my, &mz); // check possible scrollbar stuff first if (menu->is_scroll_box) { int arrow_width, arrow_height, aw, ScrollAllow=0; static fix64 ScrollTime=0; if (ScrollTime + F1_0/5 < timer_query()) { ScrollTime = timer_query(); ScrollAllow = 1; } if (menu->scroll_offset != 0) { gr_get_string_size(UP_ARROW_MARKER, &arrow_width, &arrow_height, &aw); x1 = grd_curcanv->cv_bitmap.bm_x+BORDERX-FSPACX(12); y1 = grd_curcanv->cv_bitmap.bm_y + menu->items[menu->scroll_offset].y-(((int)LINE_SPACING)*menu->scroll_offset); x2 = x1 + arrow_width; y2 = y1 + arrow_height; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && ScrollAllow) { newmenu_scroll(menu, -1); } } if (menu->scroll_offset+menu->max_displayablenitems) { gr_get_string_size(DOWN_ARROW_MARKER, &arrow_width, &arrow_height, &aw); x1 = grd_curcanv->cv_bitmap.bm_x+BORDERX-FSPACX(12); y1 = grd_curcanv->cv_bitmap.bm_y + menu->items[menu->scroll_offset+menu->max_displayable-1].y-(((int)LINE_SPACING)*menu->scroll_offset); x2 = x1 + arrow_width; y2 = y1 + arrow_height; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && ScrollAllow) { newmenu_scroll(menu, 1); } } } for (i=menu->scroll_offset; imax_on_menu+menu->scroll_offset; i++ ) { x1 = grd_curcanv->cv_bitmap.bm_x + menu->items[i].x-FSPACX(13); x2 = x1 + menu->items[i].w+FSPACX(13); y1 = grd_curcanv->cv_bitmap.bm_y + menu->items[i].y - (((int)LINE_SPACING)*menu->scroll_offset); y2 = y1 + menu->items[i].h; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && (menu->items[i].type != NM_TYPE_TEXT) ) { if (i != menu->citem) { if(Hack_DblClick_MenuMode) menu->dblclick_flag = 0; } menu->citem = i; if ( menu->items[menu->citem].type == NM_TYPE_SLIDER ) { char slider_text[NM_MAX_TEXT_LEN+1], *p, *s1; int slider_width, height, aw, sleft_width, sright_width, smiddle_width; strcpy(slider_text, menu->items[menu->citem].saved_text); p = strchr(slider_text, '\t'); if (p) { *p = '\0'; s1 = p+1; } if (p) { gr_get_string_size(s1, &slider_width, &height, &aw); gr_get_string_size(SLIDER_LEFT, &sleft_width, &height, &aw); gr_get_string_size(SLIDER_RIGHT, &sright_width, &height, &aw); gr_get_string_size(SLIDER_MIDDLE, &smiddle_width, &height, &aw); x1 = grd_curcanv->cv_bitmap.bm_x + menu->items[menu->citem].x + menu->items[menu->citem].w - slider_width; x2 = x1 + slider_width + sright_width; if ( (mx > x1) && (mx < (x1 + sleft_width)) && (menu->items[menu->citem].value != menu->items[menu->citem].min_value) ) { menu->items[menu->citem].value = menu->items[menu->citem].min_value; changed = 1; } else if ( (mx < x2) && (mx > (x2 - sright_width)) && (menu->items[menu->citem].value != menu->items[menu->citem].max_value) ) { menu->items[menu->citem].value = menu->items[menu->citem].max_value; changed = 1; } else if ( (mx > (x1 + sleft_width)) && (mx < (x2 - sright_width)) ) { int num_values, value_width, new_value; num_values = menu->items[menu->citem].max_value - menu->items[menu->citem].min_value + 1; value_width = (slider_width - sleft_width - sright_width) / num_values; new_value = (mx - x1 - sleft_width) / value_width; if ( menu->items[menu->citem].value != new_value ) { menu->items[menu->citem].value = new_value; changed = 1; } } *p = '\t'; } } if (menu->citem == old_choice) break; if ((menu->items[menu->citem].type==NM_TYPE_INPUT) && (menu->citem!=old_choice)) menu->items[menu->citem].value = -1; if ((old_choice>-1) && (menu->items[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=menu->citem)) { menu->items[old_choice].group=0; strcpy(menu->items[old_choice].text, menu->items[old_choice].saved_text ); menu->items[old_choice].value = -1; } break; } } } if ((event->type == EVENT_MOUSE_BUTTON_UP) && !menu->all_text && (menu->citem != -1) && (menu->items[menu->citem].type == NM_TYPE_MENU) ) { mouse_get_pos(&mx, &my, &mz); for (i=menu->scroll_offset; imax_on_menu+menu->scroll_offset; i++ ) { x1 = grd_curcanv->cv_bitmap.bm_x + menu->items[i].x-FSPACX(13); x2 = x1 + menu->items[i].w+FSPACX(13); y1 = grd_curcanv->cv_bitmap.bm_y + menu->items[i].y - (((int)LINE_SPACING)*menu->scroll_offset); y2 = y1 + menu->items[i].h; if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) { if (Hack_DblClick_MenuMode) { if (menu->dblclick_flag) { // Tell callback, allow staying in menu event->type = EVENT_NEWMENU_SELECTED; if (menu->subfunction && (*menu->subfunction)(menu, event, menu->userdata)) return 1; if (menu->rval) *menu->rval = menu->citem; window_close(menu->wind); gr_set_current_canvas(save_canvas); return 1; } else menu->dblclick_flag = 1; } else { // Tell callback, allow staying in menu event->type = EVENT_NEWMENU_SELECTED; if (menu->subfunction && (*menu->subfunction)(menu, event, menu->userdata)) return 1; if (menu->rval) *menu->rval = menu->citem; window_close(menu->wind); gr_set_current_canvas(save_canvas); return 1; } } } } if ((event->type == EVENT_MOUSE_BUTTON_UP) && (menu->citem>-1) && (menu->items[menu->citem].type==NM_TYPE_INPUT_MENU) && (menu->items[menu->citem].group==0)) { menu->items[menu->citem].group = 1; if ( !d_strnicmp( menu->items[menu->citem].saved_text, TXT_EMPTY, strlen(TXT_EMPTY) ) ) { menu->items[menu->citem].text[0] = 0; menu->items[menu->citem].value = -1; } else { strip_end_whitespace(menu->items[menu->citem].text); } } gr_set_current_canvas(save_canvas); if (changed && menu->subfunction) { event->type = EVENT_NEWMENU_CHANGED; (*menu->subfunction)(menu, event, menu->userdata); } break; } case MBTN_RIGHT: if (menu->mouse_state) { if ( (menu->citem>-1) && (menu->items[menu->citem].type==NM_TYPE_INPUT_MENU) && (menu->items[menu->citem].group==1)) { menu->items[menu->citem].group=0; strcpy(menu->items[menu->citem].text, menu->items[menu->citem].saved_text ); menu->items[menu->citem].value = -1; } else { window_close(menu->wind); return 1; } } break; case MBTN_Z_UP: if (menu->mouse_state) newmenu_scroll(menu, -1); break; case MBTN_Z_DOWN: if (menu->mouse_state) newmenu_scroll(menu, 1); break; } return 0; } int newmenu_key_command(window *wind, d_event *event, newmenu *menu) { newmenu_item *item = &menu->items[menu->citem]; int k = event_key_get(event); int old_choice, i; char *Temp,TempVal; int changed = 0; int rval = 1; if (keyd_pressed[KEY_NUMLOCK]) { switch( k ) { case KEY_PAD0: k = KEY_0; break; case KEY_PAD1: k = KEY_1; break; case KEY_PAD2: k = KEY_2; break; case KEY_PAD3: k = KEY_3; break; case KEY_PAD4: k = KEY_4; break; case KEY_PAD5: k = KEY_5; break; case KEY_PAD6: k = KEY_6; break; case KEY_PAD7: k = KEY_7; break; case KEY_PAD8: k = KEY_8; break; case KEY_PAD9: k = KEY_9; break; case KEY_PADPERIOD: k = KEY_PERIOD; break; } } old_choice = menu->citem; switch( k ) { case KEY_HOME: case KEY_PAD7: newmenu_scroll(menu, -menu->nitems); break; case KEY_END: case KEY_PAD1: newmenu_scroll(menu, menu->nitems); break; case KEY_TAB + KEY_SHIFTED: case KEY_UP: case KEY_PAGEUP: case KEY_PAD8: if (k == KEY_PAGEUP) newmenu_scroll(menu, -10); else newmenu_scroll(menu, -1); if ((menu->items[menu->citem].type==NM_TYPE_INPUT) && (menu->citem!=old_choice)) menu->items[menu->citem].value = -1; if ((old_choice>-1) && (menu->items[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=menu->citem)) { menu->items[old_choice].group=0; strcpy(menu->items[old_choice].text, menu->items[old_choice].saved_text ); menu->items[old_choice].value = -1; } break; case KEY_TAB: case KEY_DOWN: case KEY_PAGEDOWN: case KEY_PAD2: if (k == KEY_PAGEDOWN) newmenu_scroll(menu, 10); else newmenu_scroll(menu, 1); if ((menu->items[menu->citem].type==NM_TYPE_INPUT) && (menu->citem!=old_choice)) menu->items[menu->citem].value = -1; if ( (old_choice>-1) && (menu->items[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=menu->citem)) { menu->items[old_choice].group=0; strcpy(menu->items[old_choice].text, menu->items[old_choice].saved_text ); menu->items[old_choice].value = -1; } break; case KEY_SPACEBAR: if ( menu->citem > -1 ) { switch( item->type ) { case NM_TYPE_MENU: case NM_TYPE_INPUT: case NM_TYPE_INPUT_MENU: break; case NM_TYPE_CHECK: if ( item->value ) item->value = 0; else item->value = 1; if (menu->is_scroll_box) { if (menu->citem==(menu->max_on_menu+menu->scroll_offset-1) || menu->citem==menu->scroll_offset) { menu->last_scroll_check=-1; } } changed = 1; break; case NM_TYPE_RADIO: for (i=0; initems; i++ ) { if ((i!=menu->citem) && (menu->items[i].type==NM_TYPE_RADIO) && (menu->items[i].group==item->group) && (menu->items[i].value) ) { menu->items[i].value = 0; changed = 1; } } item->value = 1; changed = 1; break; } } break; case KEY_SHIFTED+KEY_UP: if (menu->reorderitems && menu->citem!=0) { Temp=menu->items[menu->citem].text; TempVal=menu->items[menu->citem].value; menu->items[menu->citem].text=menu->items[menu->citem-1].text; menu->items[menu->citem].value=menu->items[menu->citem-1].value; menu->items[menu->citem-1].text=Temp; menu->items[menu->citem-1].value=TempVal; menu->citem--; changed = 1; } break; case KEY_SHIFTED+KEY_DOWN: if (menu->reorderitems && menu->citem!=(menu->nitems-1)) { Temp=menu->items[menu->citem].text; TempVal=menu->items[menu->citem].value; menu->items[menu->citem].text=menu->items[menu->citem+1].text; menu->items[menu->citem].value=menu->items[menu->citem+1].value; menu->items[menu->citem+1].text=Temp; menu->items[menu->citem+1].value=TempVal; menu->citem++; changed = 1; } break; case KEY_ENTER: case KEY_PADENTER: if ( (menu->citem>-1) && (item->type==NM_TYPE_INPUT_MENU) && (item->group==0)) { item->group = 1; if ( !d_strnicmp( item->saved_text, TXT_EMPTY, strlen(TXT_EMPTY) ) ) { item->text[0] = 0; item->value = -1; } else { strip_end_whitespace(item->text); } } else { if (item->type==NM_TYPE_INPUT_MENU) item->group = 0; // go out of editing mode // Tell callback, allow staying in menu event->type = EVENT_NEWMENU_SELECTED; if (menu->subfunction && (*menu->subfunction)(menu, event, menu->userdata)) return 1; if (menu->rval) *menu->rval = menu->citem; window_close(menu->wind); return 1; } break; case KEY_ESC: if ( (menu->citem>-1) && (item->type==NM_TYPE_INPUT_MENU) && (item->group==1)) { item->group=0; strcpy(item->text, item->saved_text ); item->value = -1; } else { window_close(menu->wind); return 1; } break; #ifndef NDEBUG case KEY_BACKSP: if ( (menu->citem>-1) && (item->type!=NM_TYPE_INPUT)&&(item->type!=NM_TYPE_INPUT_MENU)) Int3(); break; #endif default: rval = 0; break; } if ( menu->citem > -1 ) { int ascii; // Alerting callback of every keypress for NM_TYPE_INPUT. Alternatively, just respond to EVENT_NEWMENU_SELECTED if ( ((item->type==NM_TYPE_INPUT)||((item->type==NM_TYPE_INPUT_MENU)&&(item->group==1)) )&& (old_choice==menu->citem) ) { if ( k==KEY_LEFT || k==KEY_BACKSP || k==KEY_PAD4 ) { if (item->value==-1) item->value = strlen(item->text); if (item->value > 0) item->value--; item->text[item->value] = 0; if (item->type==NM_TYPE_INPUT) changed = 1; rval = 1; } else { ascii = key_ascii(); if ((ascii < 255 ) && (item->value < item->text_len )) { int allowed; if (item->value==-1) { item->value = 0; } allowed = char_allowed(ascii); if (!allowed && ascii==' ' && char_allowed('_')) { ascii = '_'; allowed=1; } if (allowed) { item->text[item->value++] = ascii; item->text[item->value] = 0; if (item->type==NM_TYPE_INPUT) changed = 1; } } } } else if ((item->type!=NM_TYPE_INPUT) && (item->type!=NM_TYPE_INPUT_MENU) ) { ascii = key_ascii(); if (ascii < 255 ) { int choice1 = menu->citem; ascii = toupper(ascii); do { int i,ch; choice1++; if (choice1 >= menu->nitems ) choice1=0; for (i=0;(ch=menu->items[choice1].text[i])!=0 && ch==' ';i++); if ( ( (menu->items[choice1].type==NM_TYPE_MENU) || (menu->items[choice1].type==NM_TYPE_CHECK) || (menu->items[choice1].type==NM_TYPE_RADIO) || (menu->items[choice1].type==NM_TYPE_NUMBER) || (menu->items[choice1].type==NM_TYPE_SLIDER) ) && (ascii==toupper(ch)) ) { k = 0; menu->citem = choice1; } while (menu->citem+4>=menu->max_on_menu+menu->scroll_offset && menu->scroll_offset < menu->nitems-menu->max_on_menu) menu->scroll_offset++; while (menu->citem-4scroll_offset && menu->scroll_offset > 0) menu->scroll_offset--; } while (choice1 != menu->citem ); } } if ( (item->type==NM_TYPE_NUMBER) || (item->type==NM_TYPE_SLIDER)) { switch( k ) { case KEY_LEFT: case KEY_PAD4: item->value -= 1; changed = 1; rval = 1; break; case KEY_RIGHT: case KEY_PAD6: item->value++; changed = 1; rval = 1; break; case KEY_SPACEBAR: item->value += 10; changed = 1; rval = 1; break; case KEY_BACKSP: item->value -= 10; changed = 1; rval = 1; break; } if (item->value < item->min_value) item->value=item->min_value; if (item->value > item->max_value) item->value=item->max_value; } } if (changed && menu->subfunction) { event->type = EVENT_NEWMENU_CHANGED; (*menu->subfunction)(menu, event, menu->userdata); } return rval; } void newmenu_create_structure( newmenu *menu ) { int i,j,aw, tw, th, twidth,fm,right_offset; int nmenus, nothers; grs_font *save_font; grs_canvas *save_canvas; int string_width, string_height, average_width; save_canvas = grd_curcanv; gr_set_current_canvas(NULL); save_font = grd_curcanv->cv_font; tw = th = 0; if ( menu->title ) { gr_set_curfont(HUGE_FONT); gr_get_string_size(menu->title,&string_width,&string_height,&average_width ); tw = string_width; th = string_height; } if ( menu->subtitle ) { gr_set_curfont(MEDIUM3_FONT); gr_get_string_size(menu->subtitle,&string_width,&string_height,&average_width ); if (string_width > tw ) tw = string_width; th += string_height; } th += FSPACY(5); //put some space between titles & body gr_set_curfont(menu->tiny_mode?GAME_FONT:MEDIUM1_FONT); menu->w = aw = 0; menu->h = th; nmenus = nothers = 0; // Find menu height & width (store in w,h) for (i=0; initems; i++ ) { menu->items[i].y = menu->h; gr_get_string_size(menu->items[i].text,&string_width,&string_height,&average_width ); menu->items[i].right_offset = 0; menu->items[i].saved_text[0] = '\0'; if ( menu->items[i].type == NM_TYPE_SLIDER ) { int index,w1,h1,aw1; nothers++; index = sprintf( menu->items[i].saved_text, "%s", SLIDER_LEFT ); for (j=0; j<(menu->items[i].max_value-menu->items[i].min_value+1); j++ ) { index+= sprintf( menu->items[i].saved_text + index, "%s", SLIDER_MIDDLE ); } sprintf( menu->items[i].saved_text + index, "%s", SLIDER_RIGHT ); gr_get_string_size(menu->items[i].saved_text,&w1,&h1,&aw1 ); string_width += w1 + aw; } if ( menu->items[i].type == NM_TYPE_MENU ) { nmenus++; } if ( menu->items[i].type == NM_TYPE_CHECK ) { int w1,h1,aw1; nothers++; gr_get_string_size(NORMAL_CHECK_BOX, &w1, &h1, &aw1 ); menu->items[i].right_offset = w1; gr_get_string_size(CHECKED_CHECK_BOX, &w1, &h1, &aw1 ); if (w1 > menu->items[i].right_offset) menu->items[i].right_offset = w1; } if (menu->items[i].type == NM_TYPE_RADIO ) { int w1,h1,aw1; nothers++; gr_get_string_size(NORMAL_RADIO_BOX, &w1, &h1, &aw1 ); menu->items[i].right_offset = w1; gr_get_string_size(CHECKED_RADIO_BOX, &w1, &h1, &aw1 ); if (w1 > menu->items[i].right_offset) menu->items[i].right_offset = w1; } if (menu->items[i].type==NM_TYPE_NUMBER ) { int w1,h1,aw1; char test_text[20]; nothers++; sprintf( test_text, "%d", menu->items[i].max_value ); gr_get_string_size( test_text, &w1, &h1, &aw1 ); menu->items[i].right_offset = w1; sprintf( test_text, "%d", menu->items[i].min_value ); gr_get_string_size( test_text, &w1, &h1, &aw1 ); if ( w1 > menu->items[i].right_offset) menu->items[i].right_offset = w1; } if ((menu->items[i].type == NM_TYPE_INPUT) || (menu->items[i].type == NM_TYPE_INPUT_MENU)) { Assert( strlen(menu->items[i].text) < NM_MAX_TEXT_LEN ); strcpy(menu->items[i].saved_text, menu->items[i].text ); string_width = menu->items[i].text_len*FSPACX(8)+menu->items[i].text_len; if ( menu->items[i].type == NM_TYPE_INPUT && string_width > MAX_TEXT_WIDTH ) string_width = MAX_TEXT_WIDTH; menu->items[i].value = -1; menu->items[i].group = 0; if (menu->items[i].type == NM_TYPE_INPUT_MENU) nmenus++; else nothers++; } menu->items[i].w = string_width; menu->items[i].h = string_height; if ( string_width > menu->w ) menu->w = string_width; // Save maximum width if ( average_width > aw ) aw = average_width; menu->h += string_height+FSPACY(1); // Find the height of all strings } if (i > menu->max_on_menu) { menu->is_scroll_box=1; menu->h = th+(LINE_SPACING*menu->max_on_menu); menu->max_displayable=menu->max_on_menu; // if our last citem was > menu->max_on_menu, make sure we re-scroll when we call this menu again if (menu->citem > menu->max_on_menu-4) { menu->scroll_offset = menu->citem - (menu->max_on_menu-4); if (menu->scroll_offset + menu->max_on_menu > menu->nitems) menu->scroll_offset = menu->nitems - menu->max_on_menu; } } else { menu->is_scroll_box=0; menu->max_on_menu=i; } right_offset=0; for (i=0; initems; i++ ) { menu->items[i].w = menu->w; if (menu->items[i].right_offset > right_offset ) right_offset = menu->items[i].right_offset; } menu->w += right_offset; twidth = 0; if ( tw > menu->w ) { twidth = ( tw - menu->w )/2; menu->w = tw; } // Find min point of menu border menu->w += BORDERX*2; menu->h += BORDERY*2; menu->x = (GWIDTH-menu->w)/2; menu->y = (GHEIGHT-menu->h)/2; if ( menu->x < 0 ) menu->x = 0; if ( menu->y < 0 ) menu->y = 0; nm_draw_background1( menu->filename ); // Update all item's x & y values. for (i=0; initems; i++ ) { menu->items[i].x = BORDERX + twidth + right_offset; menu->items[i].y += BORDERY; if ( menu->items[i].type==NM_TYPE_RADIO ) { fm = -1; // find first marked one for ( j=0; jnitems; j++ ) { if ( menu->items[j].type==NM_TYPE_RADIO && menu->items[j].group==menu->items[i].group ) { if (fm==-1 && menu->items[j].value) fm = j; menu->items[j].value = 0; } } if ( fm>=0 ) menu->items[fm].value=1; else menu->items[i].value=1; } } if (menu->citem != -1) { if (menu->citem < 0 ) menu->citem = 0; if (menu->citem > menu->nitems-1 ) menu->citem = menu->nitems-1; #ifdef NEWMENU_MOUSE menu->dblclick_flag = 1; #endif i = 0; while ( menu->items[menu->citem].type==NM_TYPE_TEXT ) { menu->citem++; i++; if (menu->citem >= menu->nitems ) { menu->citem=0; } if (i > menu->nitems ) { menu->citem=0; menu->all_text=1; break; } } } menu->mouse_state = 0; menu->swidth = SWIDTH; menu->sheight = SHEIGHT; menu->fntscalex = FNTScaleX; menu->fntscaley = FNTScaleY; gr_set_curfont(save_font); gr_set_current_canvas(save_canvas); } int newmenu_draw(window *wind, newmenu *menu) { grs_canvas *menu_canvas = window_get_canvas(wind), *save_canvas = grd_curcanv; int th = 0, ty, sx, sy; int i; int string_width, string_height, average_width; if (menu->swidth != SWIDTH || menu->sheight != SHEIGHT || menu->fntscalex != FNTScaleX || menu->fntscalex != FNTScaleY) { newmenu_create_structure ( menu ); if (menu_canvas) { gr_init_sub_canvas(menu_canvas, &grd_curscreen->sc_canvas, menu->x, menu->y, menu->w, menu->h); } } gr_set_current_canvas( NULL ); nm_draw_background1(menu->filename); if (menu->filename == NULL) nm_draw_background(menu->x-(menu->is_scroll_box?FSPACX(5):0),menu->y,menu->x+menu->w,menu->y+menu->h); gr_set_current_canvas( menu_canvas ); ty = BORDERY; if ( menu->title ) { gr_set_curfont(HUGE_FONT); gr_set_fontcolor( BM_XRGB(31,31,31), -1 ); gr_get_string_size(menu->title,&string_width,&string_height,&average_width ); th = string_height; gr_string( 0x8000, ty, menu->title ); } if ( menu->subtitle ) { gr_set_curfont(MEDIUM3_FONT); gr_set_fontcolor( BM_XRGB(21,21,21), -1 ); gr_get_string_size(menu->subtitle,&string_width,&string_height,&average_width ); gr_string( 0x8000, ty+th, menu->subtitle ); } gr_set_curfont(menu->tiny_mode?GAME_FONT:MEDIUM1_FONT); // Redraw everything... for (i=menu->scroll_offset; imax_displayable+menu->scroll_offset; i++ ) { draw_item( &menu->items[i], (i==menu->citem && !menu->all_text),menu->tiny_mode, menu->tabs_flag, menu->scroll_offset ); } if (menu->is_scroll_box) { menu->last_scroll_check=menu->scroll_offset; gr_set_curfont(menu->tiny_mode?GAME_FONT:MEDIUM2_FONT); sy=menu->items[menu->scroll_offset].y-(((int)LINE_SPACING)*menu->scroll_offset); sx=BORDERX-FSPACX(12); if (menu->scroll_offset!=0) gr_printf( sx, sy, UP_ARROW_MARKER ); else gr_printf( sx, sy, " " ); sy=menu->items[menu->scroll_offset+menu->max_displayable-1].y-(((int)LINE_SPACING)*menu->scroll_offset); sx=BORDERX-FSPACX(12); if (menu->scroll_offset+menu->max_displayablenitems) gr_printf( sx, sy, DOWN_ARROW_MARKER ); else gr_printf( sx, sy, " " ); } { d_event event; event.type = EVENT_NEWMENU_DRAW; if (menu->subfunction) (*menu->subfunction)(menu, &event, menu->userdata); } gr_set_current_canvas(save_canvas); return 1; } int newmenu_handler(window *wind, d_event *event, newmenu *menu) { if (event->type == EVENT_WINDOW_CLOSED) return 0; if (menu->subfunction) { int rval = (*menu->subfunction)(menu, event, menu->userdata); if (!window_exists(wind)) return 1; // some subfunction closed the window: bail! if (rval) { if (rval < -1) { if (menu->rval) *menu->rval = rval; window_close(wind); } return 1; // event handled } } switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); event_toggle_focus(0); key_toggle_repeat(1); break; case EVENT_WINDOW_DEACTIVATED: //event_toggle_focus(1); // No cursor recentering key_toggle_repeat(0); menu->mouse_state = 0; break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: { int button = event_mouse_get_button(event); menu->mouse_state = event->type == EVENT_MOUSE_BUTTON_DOWN; return newmenu_mouse(wind, event, menu, button); } case EVENT_KEY_COMMAND: return newmenu_key_command(wind, event, menu); break; case EVENT_IDLE: timer_delay2(50); return newmenu_mouse(wind, event, menu, -1); break; case EVENT_WINDOW_DRAW: return newmenu_draw(wind, menu); break; case EVENT_WINDOW_CLOSE: d_free(menu); break; default: break; } return 0; } newmenu *newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int citem, char * filename, int TinyMode, int TabsFlag ) { window *wind = NULL; newmenu *menu; MALLOC(menu, newmenu, 1); if (!menu) return NULL; memset(menu, 0, sizeof(newmenu)); menu->citem = citem; menu->scroll_offset = 0; menu->last_scroll_check = -1; menu->all_text = 0; menu->is_scroll_box = 0; menu->max_on_menu = TinyMode?MAXDISPLAYABLEITEMSTINY:MAXDISPLAYABLEITEMS; menu->dblclick_flag = 0; menu->title = title; menu->subtitle = subtitle; menu->nitems = nitems; menu->subfunction = subfunction; menu->items = item; menu->filename = filename; menu->tiny_mode = TinyMode; menu->tabs_flag = TabsFlag; menu->reorderitems = 0; // will be set if needed menu->rval = NULL; // Default to not returning a value - respond to EVENT_NEWMENU_SELECTED instead menu->userdata = userdata; newmenu_free_background(); if (nitems < 1 ) { d_free(menu); return NULL; } menu->max_displayable=nitems; //set_screen_mode(SCREEN_MENU); //hafta set the screen mode here or fonts might get changed/freed up if screen res changes newmenu_create_structure(menu); // Create the basic window if (menu) wind = window_create(&grd_curscreen->sc_canvas, menu->x, menu->y, menu->w, menu->h, (int (*)(window *, d_event *, void *))newmenu_handler, menu); if (!wind) { d_free(menu); return NULL; } menu->wind = wind; return menu; } int nm_messagebox1( char *title, int (*subfunction)(newmenu *menu, d_event *event, void *userdata), void *userdata, int nchoices, ... ) { int i; char * format; va_list args; char *s; char nm_text[MESSAGEBOX_TEXT_SIZE]; newmenu_item nm_message_items[5]; va_start(args, nchoices ); Assert( nchoices <= 5 ); for (i=0; i 1 ) { // PHYSFS_delete(items[*citem]); // Delete the file // for (i=*citem; i<*nitems-1; i++ ) { // items[i] = items[i+1]; // } // *nitems = *nitems - 1; // d_free( items[*nitems] ); // items[*nitems] = NULL; // return 1; // redraw; // } // *keypress = 0; // } // return 0; // } #define LB_ITEMS_ON_SCREEN 8 struct listbox { window *wind; char *title; int nitems; char **item; int allow_abort_flag; int (*listbox_callback)(listbox *lb, d_event *event, void *userdata); int citem, first_item; int marquee_maxchars, marquee_charpos, marquee_scrollback; fix64 marquee_lasttime; // to scroll text if string does not fit in box int box_w, height, box_x, box_y, title_height; short swidth, sheight; float fntscalex, fntscaley; // with these we check if resolution or fonts have changed so listbox structure can be recreated int mouse_state; void *userdata; }; char **listbox_get_items(listbox *lb) { return lb->item; } int listbox_get_nitems(listbox *lb) { return lb->nitems; } int listbox_get_citem(listbox *lb) { return lb->citem; } window *listbox_get_window(listbox *lb) { return lb->wind; } void listbox_delete_item(listbox *lb, int item) { int i; Assert(item >= 0); if (lb->nitems) { for (i=item; initems-1; i++ ) lb->item[i] = lb->item[i+1]; lb->nitems--; lb->item[lb->nitems] = NULL; if (lb->citem >= lb->nitems) lb->citem = lb->nitems ? lb->nitems - 1 : 0; } } void update_scroll_position(listbox *lb) { if (lb->citem<0) lb->citem = 0; if (lb->citem>=lb->nitems) lb->citem = lb->nitems-1; if (lb->citem< lb->first_item) lb->first_item = lb->citem; if (lb->citem>=( lb->first_item+LB_ITEMS_ON_SCREEN)) lb->first_item = lb->citem-LB_ITEMS_ON_SCREEN+1; if (lb->nitems <= LB_ITEMS_ON_SCREEN ) lb->first_item = 0; if (lb->first_item>lb->nitems-LB_ITEMS_ON_SCREEN) lb->first_item = lb->nitems-LB_ITEMS_ON_SCREEN; if (lb->first_item < 0 ) lb->first_item = 0; } int listbox_mouse(window *wind, d_event *event, listbox *lb, int button) { int i, mx, my, mz, x1, x2, y1, y2; switch (button) { case MBTN_LEFT: { if (lb->mouse_state) { int w, h, aw; mouse_get_pos(&mx, &my, &mz); for (i=lb->first_item; ifirst_item+LB_ITEMS_ON_SCREEN; i++ ) { if (i >= lb->nitems) break; gr_get_string_size(lb->item[i], &w, &h, &aw ); x1 = lb->box_x; x2 = lb->box_x + lb->box_w; y1 = (i-lb->first_item)*LINE_SPACING+lb->box_y; y2 = y1+h; if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) { lb->citem = i; return 1; } } } else if (event->type == EVENT_MOUSE_BUTTON_UP) { int w, h, aw; if (lb->citem < 0) return 0; mouse_get_pos(&mx, &my, &mz); gr_get_string_size(lb->item[lb->citem], &w, &h, &aw ); x1 = lb->box_x; x2 = lb->box_x + lb->box_w; y1 = (lb->citem-lb->first_item)*LINE_SPACING+lb->box_y; y2 = y1+h; if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) { // Tell callback, allow staying in menu event->type = EVENT_NEWMENU_SELECTED; if (lb->listbox_callback && (*lb->listbox_callback)(lb, event, lb->userdata)) return 1; window_close(wind); return 1; } } break; } case MBTN_RIGHT: { if (lb->allow_abort_flag && lb->mouse_state) { lb->citem = -1; window_close(wind); return 1; } break; } case MBTN_Z_UP: { if (lb->mouse_state) { lb->citem--; update_scroll_position(lb); } break; } case MBTN_Z_DOWN: { if (lb->mouse_state) { lb->citem++; update_scroll_position(lb); } break; } default: break; } return 0; } int listbox_key_command(window *wind, d_event *event, listbox *lb) { int key = event_key_get(event); int rval = 1; switch(key) { case KEY_HOME: case KEY_PAD7: lb->citem = 0; break; case KEY_END: case KEY_PAD1: lb->citem = lb->nitems-1; break; case KEY_UP: case KEY_PAD8: lb->citem--; break; case KEY_DOWN: case KEY_PAD2: lb->citem++; break; case KEY_PAGEDOWN: case KEY_PAD3: lb->citem += LB_ITEMS_ON_SCREEN; break; case KEY_PAGEUP: case KEY_PAD9: lb->citem -= LB_ITEMS_ON_SCREEN; break; case KEY_ESC: if (lb->allow_abort_flag) { lb->citem = -1; window_close(wind); return 1; } break; case KEY_ENTER: case KEY_PADENTER: // Tell callback, allow staying in menu event->type = EVENT_NEWMENU_SELECTED; if (lb->listbox_callback && (*lb->listbox_callback)(lb, event, lb->userdata)) return 1; window_close(wind); return 1; break; default: { int ascii = key_ascii(); if ( ascii < 255 ) { int cc,cc1; cc=cc1=lb->citem+1; if (cc1 < 0 ) cc1 = 0; if (cc1 >= lb->nitems ) cc1 = 0; while(1) { if ( cc < 0 ) cc = 0; if ( cc >= lb->nitems ) cc = 0; if ( lb->citem == cc ) break; if ( toupper( lb->item[cc][0] ) == toupper(ascii) ) { lb->citem = cc; break; } cc++; } } rval = 0; } } update_scroll_position(lb); return rval; } void listbox_create_structure( listbox *lb) { int i = 0; gr_set_current_canvas(NULL); gr_set_curfont(MEDIUM3_FONT); lb->box_w = 0; for (i=0; initems; i++ ) { int w, h, aw; gr_get_string_size( lb->item[i], &w, &h, &aw ); if ( w > lb->box_w ) lb->box_w = w+FSPACX(10); } lb->height = LINE_SPACING * LB_ITEMS_ON_SCREEN; { int w, h, aw; gr_get_string_size( lb->title, &w, &h, &aw ); if ( w > lb->box_w ) lb->box_w = w; lb->title_height = h+FSPACY(5); } lb->marquee_maxchars = lb->marquee_charpos = lb->marquee_scrollback = lb->marquee_lasttime = 0; // The box is bigger than we can fit on the screen since at least one string is too long. Check how many chars we can fit on the screen (at least only - MEDIUM*_FONT is variable font!) so we can make a marquee-like effect. if (lb->box_w + (BORDERX*2) > SWIDTH) { int w = 0, h = 0, aw = 0; lb->box_w = SWIDTH - (BORDERX*2); gr_get_string_size("O", &w, &h, &aw); lb->marquee_maxchars = lb->box_w/w; lb->marquee_lasttime = timer_query(); } lb->box_x = (grd_curcanv->cv_bitmap.bm_w-lb->box_w)/2; lb->box_y = (grd_curcanv->cv_bitmap.bm_h-(lb->height+lb->title_height))/2 + lb->title_height; if ( lb->box_y < lb->title_height ) lb->box_y = lb->title_height; if ( lb->citem < 0 ) lb->citem = 0; if ( lb->citem >= lb->nitems ) lb->citem = 0; lb->first_item = 0; update_scroll_position(lb); lb->mouse_state = 0; //dblclick_flag = 0; lb->swidth = SWIDTH; lb->sheight = SHEIGHT; lb->fntscalex = FNTScaleX; lb->fntscaley = FNTScaleY; } int listbox_draw(window *wind, listbox *lb) { int i; if (lb->swidth != SWIDTH || lb->sheight != SHEIGHT || lb->fntscalex != FNTScaleX || lb->fntscalex != FNTScaleY) listbox_create_structure ( lb ); gr_set_current_canvas(NULL); nm_draw_background( lb->box_x-BORDERX,lb->box_y-lb->title_height-BORDERY,lb->box_x+lb->box_w+BORDERX,lb->box_y+lb->height+BORDERY ); gr_set_curfont(MEDIUM3_FONT); gr_string( 0x8000, lb->box_y - lb->title_height, lb->title ); gr_setcolor( BM_XRGB( 0,0,0) ); for (i=lb->first_item; ifirst_item+LB_ITEMS_ON_SCREEN; i++ ) { int y = (i-lb->first_item)*LINE_SPACING+lb->box_y; if ( i >= lb->nitems ) { gr_setcolor( BM_XRGB(5,5,5)); gr_rect( lb->box_x + lb->box_w - FSPACX(1), y-FSPACY(1), lb->box_x + lb->box_w, y + LINE_SPACING); gr_setcolor( BM_XRGB(2,2,2)); gr_rect( lb->box_x - FSPACX(1), y - FSPACY(1), lb->box_x, y + LINE_SPACING ); gr_setcolor( BM_XRGB(0,0,0)); gr_rect( lb->box_x, y - FSPACY(1), lb->box_x + lb->box_w - FSPACX(1), y + LINE_SPACING); } else { gr_set_curfont(( i == lb->citem )?MEDIUM2_FONT:MEDIUM1_FONT); gr_setcolor( BM_XRGB(5,5,5)); gr_rect( lb->box_x + lb->box_w - FSPACX(1), y-FSPACY(1), lb->box_x + lb->box_w, y + LINE_SPACING); gr_setcolor( BM_XRGB(2,2,2)); gr_rect( lb->box_x - FSPACX(1), y - FSPACY(1), lb->box_x, y + LINE_SPACING ); gr_setcolor( BM_XRGB(0,0,0)); gr_rect( lb->box_x, y - FSPACY(1), lb->box_x + lb->box_w - FSPACX(1), y + LINE_SPACING); if (lb->marquee_maxchars && strlen(lb->item[i]) > lb->marquee_maxchars) { char *shrtstr = d_malloc(lb->marquee_maxchars+1); static int prev_citem = -1; if (prev_citem != lb->citem) { lb->marquee_charpos = lb->marquee_scrollback = 0; lb->marquee_lasttime = timer_query(); prev_citem = lb->citem; } memset(shrtstr, '\0', lb->marquee_maxchars+1); if (i == lb->citem) { if (lb->marquee_lasttime + (F1_0/3) < timer_query()) { lb->marquee_charpos = lb->marquee_charpos+(lb->marquee_scrollback?-1:+1); lb->marquee_lasttime = timer_query(); } if (lb->marquee_charpos < 0) // reached beginning of string -> scroll forward { lb->marquee_charpos = 0; lb->marquee_scrollback = 0; } if (lb->marquee_charpos + lb->marquee_maxchars - 1 > strlen(lb->item[i])) // reached end of string -> scroll backward { lb->marquee_charpos = strlen(lb->item[i]) - lb->marquee_maxchars + 1; lb->marquee_scrollback = 1; } snprintf(shrtstr, lb->marquee_maxchars, "%s", lb->item[i]+lb->marquee_charpos); } else { snprintf(shrtstr, lb->marquee_maxchars, "%s", lb->item[i]); } gr_string( lb->box_x+FSPACX(5), y, shrtstr ); d_free(shrtstr); } else { gr_string( lb->box_x+FSPACX(5), y, lb->item[i] ); } } } { d_event event; event.type = EVENT_NEWMENU_DRAW; if ( lb->listbox_callback ) (*lb->listbox_callback)(lb, &event, lb->userdata); } return 1; } int listbox_handler(window *wind, d_event *event, listbox *lb) { if (event->type == EVENT_WINDOW_CLOSED) return 0; if (lb->listbox_callback) { int rval = (*lb->listbox_callback)(lb, event, lb->userdata); if (rval) return 1; // event handled } switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); event_toggle_focus(0); key_toggle_repeat(1); break; case EVENT_WINDOW_DEACTIVATED: //event_toggle_focus(1); // No cursor recentering key_toggle_repeat(0); break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: { int button = event_mouse_get_button(event); lb->mouse_state = event->type == EVENT_MOUSE_BUTTON_DOWN; return listbox_mouse(wind, event, lb, button); } case EVENT_KEY_COMMAND: return listbox_key_command(wind, event, lb); break; case EVENT_IDLE: timer_delay2(50); return listbox_mouse(wind, event, lb, -1); break; case EVENT_WINDOW_DRAW: return listbox_draw(wind, lb); break; case EVENT_WINDOW_CLOSE: d_free(lb); break; default: break; } return 0; } listbox *newmenu_listbox( char * title, int nitems, char * items[], int allow_abort_flag, int (*listbox_callback)(listbox *lb, d_event *event, void *userdata), void *userdata ) { return newmenu_listbox1( title, nitems, items, allow_abort_flag, 0, listbox_callback, userdata ); } listbox *newmenu_listbox1( char * title, int nitems, char * items[], int allow_abort_flag, int default_item, int (*listbox_callback)(listbox *lb, d_event *event, void *userdata), void *userdata ) { listbox *lb; window *wind; MALLOC(lb, listbox, 1); if (!lb) return NULL; memset(lb, 0, sizeof(listbox)); newmenu_free_background(); lb->title = title; lb->nitems = nitems; lb->item = items; lb->citem = default_item; lb->allow_abort_flag = allow_abort_flag; lb->listbox_callback = listbox_callback; lb->userdata = userdata; set_screen_mode(SCREEN_MENU); //hafta set the screen mode here or fonts might get changed/freed up if screen res changes listbox_create_structure(lb); wind = window_create(&grd_curscreen->sc_canvas, lb->box_x-BORDERX, lb->box_y-lb->title_height-BORDERY, lb->box_w+2*BORDERX, lb->height+2*BORDERY, (int (*)(window *, d_event *, void *))listbox_handler, lb); if (!wind) { d_free(lb); return NULL; } lb->wind = wind; return lb; } //added on 10/14/98 by Victor Rachels to attempt a fixedwidth font messagebox newmenu *nm_messagebox_fixedfont( char *title, int nchoices, ... ) { int i; char * format; va_list args; char *s; char nm_text[MESSAGEBOX_TEXT_SIZE]; newmenu_item nm_message_items[5]; va_start(args, nchoices ); Assert( nchoices <= 5 ); for (i=0; i 1 ) { // unlink( items[*citem] ); // Delete the file // for (i=*citem; i<*nitems-1; i++ ) { // items[i] = items[i+1]; // } // *nitems = *nitems - 1; // free( items[*nitems] ); // items[*nitems] = NULL; // return 1; // redraw; // } // *keypress = 0; // } // return 0; // } extern char **listbox_get_items(listbox *lb); extern int listbox_get_nitems(listbox *lb); extern int listbox_get_citem(listbox *lb); struct window *listbox_get_window(listbox *lb); extern void listbox_delete_item(listbox *lb, int item); extern listbox *newmenu_listbox(char *title, int nitems, char *items[], int allow_abort_flag, int (*listbox_callback)(listbox *lb, d_event *event, void *userdata), void *userdata); extern listbox *newmenu_listbox1(char *title, int nitems, char *items[], int allow_abort_flag, int default_item, int (*listbox_callback)(listbox *lb, d_event *event, void *userdata), void *userdata); //added on 10/14/98 by Victor Rachels to attempt a fixedwidth font messagebox newmenu *nm_messagebox_fixedfont(char *title, int nchoices, ...); //end this section addition //should be called whenever the palette changes extern void newmenu_free_background(); #define NEWMENU_MOUSE #define NORMAL_CHECK_BOX "\201" #define CHECKED_CHECK_BOX "\202" #define NORMAL_RADIO_BOX "\177" #define CHECKED_RADIO_BOX "\200" #define CURSOR_STRING "_" #define SLIDER_LEFT "\203" // 131 #define SLIDER_RIGHT "\204" // 132 #define SLIDER_MIDDLE "\205" // 133 #define SLIDER_MARKER "\206" // 134 #define UP_ARROW_MARKER "+" // 135 #define DOWN_ARROW_MARKER "+" // 136 #define BORDERX (15*(SWIDTH/320)) #define BORDERY (15*(SHEIGHT/200)) #endif /* _NEWMENU_H */ dxx-rebirth-0.58.1-d1x/main/object.c000066400000000000000000001671201217717257200171170ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * object rendering * */ #include // for memset #include #include "inferno.h" #include "game.h" #include "gr.h" #include "stdlib.h" #include "bm.h" #include "3d.h" #include "segment.h" #include "texmap.h" #include "laser.h" #include "key.h" #include "gameseg.h" #include "textures.h" #include "byteswap.h" #include "object.h" #include "physics.h" #include "slew.h" #include "render.h" #include "wall.h" #include "vclip.h" #include "polyobj.h" #include "fireball.h" #include "laser.h" #include "dxxerror.h" #include "ai.h" #include "hostage.h" #include "morph.h" #include "cntrlcen.h" #include "powerup.h" #include "fuelcen.h" #include "sounds.h" #include "collide.h" #include "lighting.h" #include "newdemo.h" #include "player.h" #include "weapon.h" #include "newmenu.h" #include "gauges.h" #include "multi.h" #include "menu.h" #include "args.h" #include "text.h" #include "piggy.h" #include "robot.h" #include "gameseq.h" #include "playsave.h" #ifdef EDITOR #include "editor/editor.h" #endif void obj_detach_all(object *parent); void obj_detach_one(object *sub); /* * Global variables */ ubyte CollisionResult[MAX_OBJECT_TYPES][MAX_OBJECT_TYPES]; object *ConsoleObject; //the object that is the player static short free_obj_list[MAX_OBJECTS]; //Data for objects // -- Object stuff //info on the various types of objects #ifndef NDEBUG object Object_minus_one; #endif object Objects[MAX_OBJECTS]; int num_objects=0; int Highest_object_index=0; int Highest_ever_object_index=0; // grs_bitmap *robot_bms[MAX_ROBOT_BITMAPS]; //all bitmaps for all robots // int robot_bm_nums[MAX_ROBOT_TYPES]; //starting bitmap num for each robot // int robot_n_bitmaps[MAX_ROBOT_TYPES]; //how many bitmaps for each robot // char *robot_names[MAX_ROBOT_TYPES]; //name of each robot //--unused-- int Num_robot_types=0; int print_object_info = 0; //@@int Object_viewer = 0; //object * Slew_object = NULL; // Object containing slew object info. //--unused-- int Player_controller_type = 0; // List of objects rendered last frame in order. Created at render time, used by homing missiles in laser.c short Ordered_rendered_object_list[MAX_RENDERED_OBJECTS]; int Num_rendered_objects = 0; #if !defined(NDEBUG) || defined(EDITOR) char Object_type_names[MAX_OBJECT_TYPES][9] = { "WALL ", "FIREBALL", "ROBOT ", "HOSTAGE ", "PLAYER ", "WEAPON ", "CAMERA ", "POWERUP ", "DEBRIS ", "CNTRLCEN", "FLARE ", "CLUTTER ", "GHOST ", "LIGHT ", "COOP ", }; #endif #ifndef RELEASE //set viewer object to next object in array void object_goto_next_viewer() { int i, start_obj = 0; start_obj = Viewer - Objects; //get viewer object number for (i=0;i<=Highest_object_index;i++) { start_obj++; if (start_obj > Highest_object_index ) start_obj = 0; if (Objects[start_obj].type != OBJ_NONE ) { Viewer = &Objects[start_obj]; return; } } Error( "Couldn't find a viewer object!" ); } #endif object *obj_find_first_of_type (int type) { int i; for (i=0;i<=Highest_object_index;i++) if (Objects[i].type==type) return (&Objects[i]); return ((object *)NULL); } //draw an object that has one bitmap & doesn't rotate void draw_object_blob(object *obj,bitmap_index bmi) { grs_bitmap * bm = &GameBitmaps[bmi.index]; vms_vector pos = obj->pos; PIGGY_PAGE_IN( bmi ); // draw these with slight offset to viewer preventing too much ugly clipping if ( obj->type == OBJ_FIREBALL && obj->id == VCLIP_VOLATILE_WALL_HIT ) { vms_vector offs_vec; vm_vec_normalized_dir_quick(&offs_vec,&Viewer->pos,&obj->pos); vm_vec_scale_add2(&pos,&offs_vec,F1_0); } if (bm->bm_w > bm->bm_h) g3_draw_bitmap(&pos,obj->size,fixmuldiv(obj->size,bm->bm_h,bm->bm_w),bm); else g3_draw_bitmap(&pos,fixmuldiv(obj->size,bm->bm_w,bm->bm_h),obj->size,bm); } //draw an object that is a texture-mapped rod void draw_object_tmap_rod(object *obj,bitmap_index bitmapi,int lighted) { grs_bitmap * bitmap = &GameBitmaps[bitmapi.index]; g3s_lrgb light; vms_vector delta,top_v,bot_v; g3s_point top_p,bot_p; PIGGY_PAGE_IN(bitmapi); vm_vec_copy_scale(&delta,&obj->orient.uvec,obj->size); vm_vec_add(&top_v,&obj->pos,&delta); vm_vec_sub(&bot_v,&obj->pos,&delta); g3_rotate_point(&top_p,&top_v); g3_rotate_point(&bot_p,&bot_v); if (lighted) { light = compute_object_light(obj,&top_p.p3_vec); } else { light.r = light.g = light.b = f1_0; } g3_draw_rod_tmap(bitmap,&bot_p,obj->size,&top_p,obj->size,light); } int Linear_tmap_polygon_objects = 1; extern fix Max_thrust; //used for robot engine glow #define MAX_VELOCITY i2f(50) //what darkening level to use when cloaked #define CLOAKED_FADE_LEVEL 28 #define CLOAK_FADEIN_DURATION_PLAYER F2_0 #define CLOAK_FADEOUT_DURATION_PLAYER F2_0 #define CLOAK_FADEIN_DURATION_ROBOT F1_0 #define CLOAK_FADEOUT_DURATION_ROBOT F1_0 //do special cloaked render static void draw_cloaked_object(object *obj,g3s_lrgb light,fix *glow,fix64 cloak_start_time,fix64 cloak_end_time) { fix cloak_delta_time,total_cloaked_time; fix light_scale=F1_0; int cloak_value=0; int fading=0; //if true, fading, else cloaking fix Cloak_fadein_duration=0; fix Cloak_fadeout_duration=0; total_cloaked_time = cloak_end_time-cloak_start_time; switch (obj->type) { case OBJ_PLAYER: Cloak_fadein_duration = CLOAK_FADEIN_DURATION_PLAYER; Cloak_fadeout_duration = CLOAK_FADEOUT_DURATION_PLAYER; break; case OBJ_ROBOT: Cloak_fadein_duration = CLOAK_FADEIN_DURATION_ROBOT; Cloak_fadeout_duration = CLOAK_FADEOUT_DURATION_ROBOT; break; default: Int3(); // Contact Mike: Unexpected object type in draw_cloaked_object. } cloak_delta_time = GameTime64 - cloak_start_time; if (cloak_delta_time < Cloak_fadein_duration/2) { light_scale = Cloak_fadein_duration/2 - cloak_delta_time; fading = 1; } else if (cloak_delta_time < Cloak_fadein_duration) { cloak_value = f2i((cloak_delta_time - Cloak_fadein_duration/2) * CLOAKED_FADE_LEVEL); } else if (GameTime64 < cloak_end_time-Cloak_fadeout_duration) { static int cloak_delta=0,cloak_dir=1; static fix cloak_timer=0; //note, if more than one cloaked object is visible at once, the //pulse rate will change! cloak_timer -= FrameTime; while (cloak_timer < 0) { cloak_timer += Cloak_fadeout_duration/12; cloak_delta += cloak_dir; if (cloak_delta==0 || cloak_delta==4) cloak_dir = -cloak_dir; } cloak_value = CLOAKED_FADE_LEVEL - cloak_delta; } else if (GameTime64 < cloak_end_time-Cloak_fadeout_duration/2) { cloak_value = f2i((total_cloaked_time - Cloak_fadeout_duration/2 - cloak_delta_time) * CLOAKED_FADE_LEVEL); } else { light_scale = Cloak_fadeout_duration/2 - (total_cloaked_time - cloak_delta_time); fading = 1; } bitmap_index * alt_textures = NULL; if ( obj->rtype.pobj_info.alt_textures > 0 ) alt_textures = multi_player_textures[obj->rtype.pobj_info.alt_textures-1]; if (fading) { fix new_glow; g3s_lrgb new_light; new_light.r = fixmul(light.r,light_scale); new_light.g = fixmul(light.g,light_scale); new_light.b = fixmul(light.b,light_scale); new_glow = fixmul(*glow,light_scale); draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles, obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags, new_light, &new_glow, alt_textures ); } else { gr_settransblend(cloak_value, GR_BLEND_NORMAL); g3_set_special_render(draw_tmap_flat,NULL,NULL); //use special flat drawer draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles, obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags, light, glow, alt_textures ); g3_set_special_render(NULL,NULL,NULL); gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } } //draw an object which renders as a polygon model void draw_polygon_object(object *obj) { g3s_lrgb light; int imsave; fix engine_glow_value[1]; light = compute_object_light(obj,NULL); // If option set for bright players in netgame, brighten them! #ifdef NETWORK if (Game_mode & GM_MULTI) if (Netgame.BrightPlayers) light.r = light.g = light.b = F1_0*2; #endif imsave = Interpolation_method; if (Linear_tmap_polygon_objects) Interpolation_method = 1; //set engine glow value engine_glow_value[0] = f1_0/5; if (obj->movement_type == MT_PHYSICS) { if (obj->mtype.phys_info.flags & PF_USES_THRUST && obj->type==OBJ_PLAYER && obj->id==Player_num) { fix thrust_mag = vm_vec_mag_quick(&obj->mtype.phys_info.thrust); engine_glow_value[0] += (fixdiv(thrust_mag,Player_ship->max_thrust)*4)/5; } else { fix speed = vm_vec_mag_quick(&obj->mtype.phys_info.velocity); engine_glow_value[0] += (fixdiv(speed,MAX_VELOCITY)*4)/5; } } if (obj->rtype.pobj_info.tmap_override != -1) { polymodel *pm = &Polygon_models[obj->rtype.pobj_info.model_num]; bitmap_index bm_ptrs[10]; int i; Assert(pm->n_textures<=10); for (i=0;in_textures;i++) bm_ptrs[i] = Textures[obj->rtype.pobj_info.tmap_override]; draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles, obj->rtype.pobj_info.model_num, obj->rtype.pobj_info.subobj_flags, light, engine_glow_value, bm_ptrs); } else { if (obj->type==OBJ_PLAYER && (Players[obj->id].flags&PLAYER_FLAGS_CLOAKED)) draw_cloaked_object(obj,light,engine_glow_value,Players[obj->id].cloak_time,Players[obj->id].cloak_time+CLOAK_TIME_MAX); else if ((obj->type == OBJ_ROBOT) && (obj->ctype.ai_info.CLOAKED)) { if (Robot_info[obj->id].boss_flag) draw_cloaked_object(obj,light,engine_glow_value, Boss_cloak_start_time, Boss_cloak_end_time); else draw_cloaked_object(obj,light,engine_glow_value, GameTime64-F1_0*10, GameTime64+F1_0*10); } else { bitmap_index * alt_textures = NULL; if ( obj->rtype.pobj_info.alt_textures > 0 ) alt_textures = multi_player_textures[obj->rtype.pobj_info.alt_textures-1]; if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) { fix dist_to_eye = vm_vec_dist_quick(&Viewer->pos, &obj->pos); gr_settransblend(GR_FADE_OFF, GR_BLEND_ADDITIVE_A); if (dist_to_eye < Simple_model_threshhold_scale * F1_0*2) draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles, Weapon_info[obj->id].model_num_inner, obj->rtype.pobj_info.subobj_flags, light, engine_glow_value, alt_textures); } draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num, obj->rtype.pobj_info.subobj_flags, light, engine_glow_value, alt_textures); #ifndef OGL // in software rendering must draw inner model last if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) { fix dist_to_eye = vm_vec_dist_quick(&Viewer->pos, &obj->pos); gr_settransblend(GR_FADE_OFF, GR_BLEND_ADDITIVE_A); if (dist_to_eye < Simple_model_threshhold_scale * F1_0*2) draw_polygon_model(&obj->pos, &obj->orient, obj->rtype.pobj_info.anim_angles, Weapon_info[obj->id].model_num_inner, obj->rtype.pobj_info.subobj_flags, light, engine_glow_value, alt_textures); } #endif if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); } } Interpolation_method = imsave; } //------------------------------------------------------------------------------ // These variables are used to keep a list of the 3 closest robots to the viewer. // The code works like this: Every time render object is called with a polygon model, // it finds the distance of that robot to the viewer. If this distance if within 10 // segments of the viewer, it does the following: If there aren't already 3 robots in // the closet-robots list, it just sticks that object into the list along with its distance. // If the list already contains 3 robots, then it finds the robot in that list that is // farthest from the viewer. If that object is farther than the object currently being // rendered, then the new object takes over that far object's slot. *Then* after all // objects are rendered, object_render_targets is called an it draws a target on top // of all the objects. //091494: #define MAX_CLOSE_ROBOTS 3 //--unused-- static int Object_draw_lock_boxes = 0; //091494: static int Object_num_close = 0; //091494: static object * Object_close_ones[MAX_CLOSE_ROBOTS]; //091494: static fix Object_close_distance[MAX_CLOSE_ROBOTS]; //091494: set_close_objects(object *obj) //091494: { //091494: fix dist; //091494: //091494: if ( (obj->type != OBJ_ROBOT) || (Object_draw_lock_boxes==0) ) //091494: return; //091494: //091494: // The following code keeps a list of the 10 closest robots to the //091494: // viewer. See comments in front of this function for how this works. //091494: dist = vm_vec_dist( &obj->pos, &Viewer->pos ); //091494: if ( dist < i2f(20*10) ) { //091494: if ( Object_num_close < MAX_CLOSE_ROBOTS ) { //091494: Object_close_ones[Object_num_close] = obj; //091494: Object_close_distance[Object_num_close] = dist; //091494: Object_num_close++; //091494: } else { //091494: int i, farthest_robot; //091494: fix farthest_distance; //091494: // Find the farthest robot in the list //091494: farthest_robot = 0; //091494: farthest_distance = Object_close_distance[0]; //091494: for (i=1; i farthest_distance ) { //091494: farthest_distance = Object_close_distance[i]; //091494: farthest_robot = i; //091494: } //091494: } //091494: // If this object is closer to the viewer than //091494: // the farthest in the list, replace the farthest with this object. //091494: if ( farthest_distance > dist ) { //091494: Object_close_ones[farthest_robot] = obj; //091494: Object_close_distance[farthest_robot] = dist; //091494: } //091494: } //091494: } //091494: } int Player_fired_laser_this_frame=-1; // ----------------------------------------------------------------------------- //this routine checks to see if an robot rendered near the middle of //the screen, and if so and the player had fired, "warns" the robot void set_robot_location_info(object *objp) { if (Player_fired_laser_this_frame != -1) { g3s_point temp; g3_rotate_point(&temp,&objp->pos); if (temp.p3_codes & CC_BEHIND) //robot behind the screen return; //the code below to check for object near the center of the screen //completely ignores z, which may not be good if ((abs(temp.p3_x) < F1_0*4) && (abs(temp.p3_y) < F1_0*4)) { objp->ctype.ai_info.danger_laser_num = Player_fired_laser_this_frame; objp->ctype.ai_info.danger_laser_signature = Objects[Player_fired_laser_this_frame].signature; } } } // ------------------------------------------------------------------------------------------------------------------ void create_small_fireball_on_object(object *objp, fix size_scale, int sound_flag) { fix size; vms_vector pos, rand_vec; int segnum; pos = objp->pos; make_random_vector(&rand_vec); vm_vec_scale(&rand_vec, objp->size/2); vm_vec_add2(&pos, &rand_vec); size = fixmul(size_scale, F1_0 + d_rand()*4); segnum = find_point_seg(&pos, objp->segnum); if (segnum != -1) { object *expl_obj; expl_obj = object_create_explosion(segnum, &pos, size, VCLIP_SMALL_EXPLOSION); if (!expl_obj) return; obj_attach(objp,expl_obj); if (d_rand() < 8192) { fix vol = F1_0/2; if (objp->type == OBJ_ROBOT) vol *= 2; if (sound_flag) digi_link_sound_to_object(SOUND_EXPLODING_WALL, objp-Objects, 0, vol); } } } // ------------------------------------------------------------------------------------------------------------------ void create_vclip_on_object(object *objp, fix size_scale, int vclip_num) { fix size; vms_vector pos, rand_vec; int segnum; pos = objp->pos; make_random_vector(&rand_vec); vm_vec_scale(&rand_vec, objp->size/2); vm_vec_add2(&pos, &rand_vec); size = fixmul(size_scale, F1_0 + d_rand()*4); segnum = find_point_seg(&pos, objp->segnum); if (segnum != -1) { object *expl_obj; expl_obj = object_create_explosion(segnum, &pos, size, vclip_num); if (!expl_obj) return; expl_obj->movement_type = MT_PHYSICS; expl_obj->mtype.phys_info.velocity.x = objp->mtype.phys_info.velocity.x/2; expl_obj->mtype.phys_info.velocity.y = objp->mtype.phys_info.velocity.y/2; expl_obj->mtype.phys_info.velocity.z = objp->mtype.phys_info.velocity.z/2; } } // -- mk, 02/05/95 -- #define VCLIP_INVULNERABILITY_EFFECT VCLIP_SMALL_EXPLOSION // -- mk, 02/05/95 -- // -- mk, 02/05/95 -- // ----------------------------------------------------------------------------- // -- mk, 02/05/95 -- void do_player_invulnerability_effect(object *objp) // -- mk, 02/05/95 -- { // -- mk, 02/05/95 -- if (d_rand() < FrameTime*8) { // -- mk, 02/05/95 -- create_vclip_on_object(objp, F1_0, VCLIP_INVULNERABILITY_EFFECT); // -- mk, 02/05/95 -- } // -- mk, 02/05/95 -- } // ----------------------------------------------------------------------------- // Render an object. Calls one of several routines based on type void render_object(object *obj) { int mld_save; if ( obj == Viewer ) return; if ( obj->type==OBJ_NONE ) { #ifndef NDEBUG Int3(); #endif return; } mld_save = Max_linear_depth; Max_linear_depth = Max_linear_depth_objects; switch (obj->render_type) { case RT_NONE: break; //doesn't render, like the player case RT_POLYOBJ: draw_polygon_object(obj); if (obj->type == OBJ_ROBOT) //"warn" robot if being shot at set_robot_location_info(obj); break; case RT_MORPH: draw_morph_object(obj); break; case RT_FIREBALL: if ( PlayerCfg.AlphaEffects ) // set nice transparency/blending for certrain objects gr_settransblend( GR_FADE_OFF, GR_BLEND_ADDITIVE_C ); draw_fireball(obj); break; case RT_WEAPON_VCLIP: if ( PlayerCfg.AlphaEffects && !is_proximity_bomb_or_smart_mine(obj->id)) // set nice transparency/blending for certain objects gr_settransblend( 7, GR_BLEND_ADDITIVE_A ); draw_weapon_vclip(obj); break; case RT_HOSTAGE: draw_hostage(obj); break; case RT_POWERUP: if ( PlayerCfg.AlphaEffects ) // set nice transparency/blending for certrain objects switch ( obj->id ) { case POW_EXTRA_LIFE: case POW_ENERGY: case POW_SHIELD_BOOST: case POW_CLOAK: case POW_INVULNERABILITY: gr_settransblend( 7, GR_BLEND_ADDITIVE_A ); break; } draw_powerup(obj); break; case RT_LASER: if ( PlayerCfg.AlphaEffects ) // set nice transparency/blending for certrain objects gr_settransblend( 7, GR_BLEND_ADDITIVE_A ); Laser_render(obj); break; default: Error("Unknown render_type <%d>",obj->render_type); } gr_settransblend( GR_FADE_OFF, GR_BLEND_NORMAL ); // revert any transparency/blending setting back to normal if ( obj->render_type != RT_NONE && Newdemo_state == ND_STATE_RECORDING ) newdemo_record_render_object(obj); Max_linear_depth = mld_save; } void check_and_fix_matrix(vms_matrix *m); #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0 void reset_player_object() { int i; //Init physics vm_vec_zero(&ConsoleObject->mtype.phys_info.velocity); vm_vec_zero(&ConsoleObject->mtype.phys_info.thrust); vm_vec_zero(&ConsoleObject->mtype.phys_info.rotvel); vm_vec_zero(&ConsoleObject->mtype.phys_info.rotthrust); ConsoleObject->mtype.phys_info.brakes = ConsoleObject->mtype.phys_info.turnroll = 0; ConsoleObject->mtype.phys_info.mass = Player_ship->mass; ConsoleObject->mtype.phys_info.drag = Player_ship->drag; ConsoleObject->mtype.phys_info.flags |= PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST; //Init render info ConsoleObject->render_type = RT_POLYOBJ; ConsoleObject->rtype.pobj_info.model_num = Player_ship->model_num; //what model is this? ConsoleObject->rtype.pobj_info.subobj_flags = 0; //zero the flags ConsoleObject->rtype.pobj_info.tmap_override = -1; //no tmap override! for (i=0;irtype.pobj_info.anim_angles[i]); // Clear misc ConsoleObject->flags = 0; } //make object0 the player, setting all relevant fields void init_player_object() { ConsoleObject->type = OBJ_PLAYER; ConsoleObject->id = 0; //no sub-types for player ConsoleObject->size = Polygon_models[Player_ship->model_num].rad; ConsoleObject->control_type = CT_SLEW; //default is player slewing ConsoleObject->movement_type = MT_PHYSICS; //change this sometime ConsoleObject->lifeleft = IMMORTAL_TIME; ConsoleObject->attached_obj = -1; reset_player_object(); } //sets up the free list & init player & whatever else void init_objects() { int i; collide_init(); for (i=0;i Highest_object_index) Highest_object_index = i; } #ifndef NDEBUG int is_object_in_seg( int segnum, int objn ) { int objnum, count = 0; for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) { if ( count > MAX_OBJECTS ) { Int3(); return count; } if ( objnum==objn ) count++; } return count; } int search_all_segments_for_object( int objnum ) { int i; int count = 0; for (i=0; i<=Highest_segment_index; i++) { count += is_object_in_seg( i, objnum ); } return count; } void johns_obj_unlink(int segnum, int objnum) { object *obj = &Objects[objnum]; segment *seg = &Segments[segnum]; Assert(objnum != -1); if (obj->prev == -1) seg->objects = obj->next; else Objects[obj->prev].next = obj->next; if (obj->next != -1) Objects[obj->next].prev = obj->prev; } void remove_incorrect_objects() { int segnum, objnum, count; for (segnum=0; segnum <= Highest_segment_index; segnum++) { count = 0; for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) { count++; #ifndef NDEBUG if ( count > MAX_OBJECTS ) { Int3(); } #endif if (Objects[objnum].segnum != segnum ) { #ifndef NDEBUG Int3(); #endif johns_obj_unlink(segnum,objnum); } } } } void remove_all_objects_but( int segnum, int objnum ) { int i; for (i=0; i<=Highest_segment_index; i++) { if (segnum != i ) { if (is_object_in_seg( i, objnum )) { johns_obj_unlink( i, objnum ); } } } } int check_duplicate_objects() { int i, count=0; for (i=0;i<=Highest_object_index;i++) { if ( Objects[i].type != OBJ_NONE ) { count = search_all_segments_for_object( i ); if ( count > 1 ) { #ifndef NDEBUG Int3(); #endif remove_all_objects_but( Objects[i].segnum, i ); return count; } } } return count; } void list_seg_objects( int segnum ) { int objnum, count = 0; for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) { count++; if ( count > MAX_OBJECTS ) { Int3(); return; } } return; } #endif //link the object into the list for its segment void obj_link(int objnum,int segnum) { object *obj = &Objects[objnum]; Assert(objnum != -1); Assert(obj->segnum == -1); Assert(segnum>=0 && segnum<=Highest_segment_index); obj->segnum = segnum; obj->next = Segments[segnum].objects; obj->prev = -1; Segments[segnum].objects = objnum; if (obj->next != -1) Objects[obj->next].prev = objnum; //list_seg_objects( segnum ); //check_duplicate_objects(); Assert(Objects[0].next != 0); if (Objects[0].next == 0) Objects[0].next = -1; Assert(Objects[0].prev != 0); if (Objects[0].prev == 0) Objects[0].prev = -1; } void obj_unlink(int objnum) { object *obj = &Objects[objnum]; segment *seg = &Segments[obj->segnum]; Assert(objnum != -1); if (obj->prev == -1) seg->objects = obj->next; else Objects[obj->prev].next = obj->next; if (obj->next != -1) Objects[obj->next].prev = obj->prev; obj->segnum = -1; Assert(Objects[0].next != 0); Assert(Objects[0].prev != 0); } // Returns a new, unique signature for a new object int obj_get_signature() { static short sig = 0; // Yes! Short! a) We do not need higher values b) the demo system only stores shorts int free = 0, i = 0; while (!free) { free = 1; sig++; if (sig < 0) sig = 0; for (i = 0; i <= MAX_OBJECTS; i++) { if ((sig == Objects[i].signature) && (Objects[i].type != OBJ_NONE)) { free = 0; } } } return sig; } int Debris_object_count=0; int Unused_object_slots; //returns the number of a free object, updating Highest_object_index. //Generally, obj_create() should be called to get an object, since it //fills in important fields and does the linking. //returns -1 if no free objects int obj_allocate(void) { int objnum; if ( num_objects >= MAX_OBJECTS ) { return -1; } objnum = free_obj_list[num_objects++]; if (objnum > Highest_object_index) { Highest_object_index = objnum; if (Highest_object_index > Highest_ever_object_index) Highest_ever_object_index = Highest_object_index; } { int i; Unused_object_slots=0; for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_NONE) Unused_object_slots++; } return objnum; } //frees up an object. Generally, obj_delete() should be called to get //rid of an object. This function deallocates the object entry after //the object has been unlinked void obj_free(int objnum) { free_obj_list[--num_objects] = objnum; Assert(num_objects >= 0); if (objnum == Highest_object_index) while (Objects[--Highest_object_index].type == OBJ_NONE); } //----------------------------------------------------------------------------- // Scan the object list, freeing down to num_used objects void free_object_slots(int num_used) { int i, olind; int obj_list[MAX_OBJECTS]; int num_already_free, num_to_free; olind = 0; num_already_free = MAX_OBJECTS - Highest_object_index - 1; if (MAX_OBJECTS - num_already_free < num_used) return; for (i=0; i<=Highest_object_index; i++) { if (Objects[i].flags & OF_SHOULD_BE_DEAD) num_already_free++; else switch (Objects[i].type) { case OBJ_NONE: num_already_free++; if (MAX_OBJECTS - num_already_free < num_used) return; break; case OBJ_WALL: case OBJ_FLARE: Int3(); // This is curious. What is an object that is a wall? break; case OBJ_FIREBALL: case OBJ_WEAPON: case OBJ_DEBRIS: obj_list[olind++] = i; break; case OBJ_ROBOT: case OBJ_HOSTAGE: case OBJ_PLAYER: case OBJ_CNTRLCEN: case OBJ_CLUTTER: case OBJ_GHOST: case OBJ_LIGHT: case OBJ_CAMERA: case OBJ_POWERUP: break; } } num_to_free = MAX_OBJECTS - num_used - num_already_free; if (num_to_free > olind) { num_to_free = olind; } for (i=0; i Highest_segment_index) return -1; Assert(ctype <= CT_CNTRLCEN); if (type==OBJ_DEBRIS && Debris_object_count>=Max_debris_objects && !PERSISTENT_DEBRIS) return -1; if (get_seg_masks(pos, segnum, 0, __FILE__, __LINE__).centermask != 0) if ((segnum=find_point_seg(pos,segnum))==-1) { return -1; //don't create this object } // Find next free object objnum = obj_allocate(); if (objnum == -1) //no free objects return -1; Assert(Objects[objnum].type == OBJ_NONE); //make sure unused obj = &Objects[objnum]; Assert(obj->segnum == -1); // Zero out object structure to keep weird bugs from happening // in uninitialized fields. memset( obj, 0, sizeof(object) ); obj->signature = obj_get_signature(); obj->type = type; obj->id = id; obj->last_pos = *pos; obj->pos = *pos; obj->size = size; obj->flags = 0; if (orient != NULL) obj->orient = *orient; obj->control_type = ctype; obj->movement_type = mtype; obj->render_type = rtype; obj->contains_type = -1; obj->lifeleft = IMMORTAL_TIME; //assume immortal obj->attached_obj = -1; if (obj->control_type == CT_POWERUP) obj->ctype.powerup_info.count = 1; // Init physics info for this object if (obj->movement_type == MT_PHYSICS) { vm_vec_zero(&obj->mtype.phys_info.velocity); vm_vec_zero(&obj->mtype.phys_info.thrust); vm_vec_zero(&obj->mtype.phys_info.rotvel); vm_vec_zero(&obj->mtype.phys_info.rotthrust); obj->mtype.phys_info.mass = 0; obj->mtype.phys_info.drag = 0; obj->mtype.phys_info.brakes = 0; obj->mtype.phys_info.turnroll = 0; obj->mtype.phys_info.flags = 0; } if (obj->render_type == RT_POLYOBJ) obj->rtype.pobj_info.tmap_override = -1; obj->shields = 20*F1_0; segnum = find_point_seg(pos,segnum); //find correct segment Assert(segnum!=-1); obj->segnum = -1; //set to zero by memset, above obj_link(objnum,segnum); // Set (or not) persistent bit in phys_info. if (obj->type == OBJ_WEAPON) { obj->mtype.phys_info.flags |= (Weapon_info[obj->id].persistent*PF_PERSISTENT); obj->ctype.laser_info.creation_time = GameTime64; obj->ctype.laser_info.last_hitobj = -1; memset(&obj->ctype.laser_info.hitobj_list, 0, sizeof(ubyte)*MAX_OBJECTS); obj->ctype.laser_info.multiplier = F1_0; } if (obj->control_type == CT_EXPLOSION) obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1; if (obj->type == OBJ_DEBRIS) Debris_object_count++; return objnum; } #ifdef EDITOR //create a copy of an object. returns new object number int obj_create_copy(int objnum, vms_vector *new_pos, int newsegnum) { int newobjnum; object *obj; // Find next free object newobjnum = obj_allocate(); if (newobjnum == -1) return -1; obj = &Objects[newobjnum]; *obj = Objects[objnum]; obj->pos = obj->last_pos = *new_pos; obj->next = obj->prev = obj->segnum = -1; obj_link(newobjnum,newsegnum); obj->signature = obj_get_signature(); //we probably should initialize sub-structures here return newobjnum; } #endif //remove object from the world void obj_delete(int objnum) { object *obj = &Objects[objnum]; Assert(objnum != -1); Assert(objnum != 0 ); Assert(obj->type != OBJ_NONE); Assert(obj != ConsoleObject); if (obj == Viewer) //deleting the viewer? Viewer = ConsoleObject; //..make the player the viewer if (obj->flags & OF_ATTACHED) //detach this from object obj_detach_one(obj); if (obj->attached_obj != -1) //detach all objects from this obj_detach_all(obj); if (obj->type == OBJ_DEBRIS) Debris_object_count--; obj_unlink(objnum); Assert(Objects[0].next != 0); obj->type = OBJ_NONE; //unused! obj->signature = -1; obj_free(objnum); } #define DEATH_SEQUENCE_LENGTH (F1_0*5) #define DEATH_SEQUENCE_EXPLODE_TIME (F1_0*2) int Player_is_dead = 0; // If !0, then player is dead, but game continues so he can watch. object *Dead_player_camera = NULL; // Object index of object watching deader. object *Viewer_save; int Player_flags_save; int Player_exploded = 0; int Death_sequence_aborted=0; int Player_eggs_dropped=0; fix Camera_to_player_dist_goal=F1_0*4; ubyte Control_type_save, Render_type_save; // ------------------------------------------------------------------------------------------------------------------ void dead_player_end(void) { if (!Player_is_dead) return; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_restore_cockpit(); Player_is_dead = 0; Player_exploded = 0; obj_delete(Dead_player_camera-Objects); Dead_player_camera = NULL; select_cockpit(PlayerCfg.CockpitMode[0]); Viewer = Viewer_save; ConsoleObject->type = OBJ_PLAYER; ConsoleObject->flags = Player_flags_save; Assert((Control_type_save == CT_FLYING) || (Control_type_save == CT_SLEW)); ConsoleObject->control_type = Control_type_save; ConsoleObject->render_type = Render_type_save; Players[Player_num].flags &= ~PLAYER_FLAGS_INVULNERABLE; Player_eggs_dropped = 0; } // ------------------------------------------------------------------------------------------------------------------ // Camera is less than size of player away from void set_camera_pos(vms_vector *camera_pos, object *objp) { int count = 0; fix camera_player_dist; fix far_scale; camera_player_dist = vm_vec_dist_quick(camera_pos, &objp->pos); if (camera_player_dist < Camera_to_player_dist_goal) { //2*objp->size) { // Camera is too close to player object, so move it away. vms_vector player_camera_vec; fvi_query fq; fvi_info hit_data; vms_vector local_p1; vm_vec_sub(&player_camera_vec, camera_pos, &objp->pos); if ((player_camera_vec.x == 0) && (player_camera_vec.y == 0) && (player_camera_vec.z == 0)) player_camera_vec.x += F1_0/16; hit_data.hit_type = HIT_WALL; far_scale = F1_0; while ((hit_data.hit_type != HIT_NONE) && (count++ < 6)) { vms_vector closer_p1; vm_vec_normalize_quick(&player_camera_vec); vm_vec_scale(&player_camera_vec, Camera_to_player_dist_goal); fq.p0 = &objp->pos; vm_vec_add(&closer_p1, &objp->pos, &player_camera_vec); // This is the actual point we want to put the camera at. vm_vec_scale(&player_camera_vec, far_scale); // ...but find a point 50% further away... vm_vec_add(&local_p1, &objp->pos, &player_camera_vec); // ...so we won't have to do as many cuts. fq.p1 = &local_p1; fq.startseg = objp->segnum; fq.rad = 0; fq.thisobjnum = objp-Objects; fq.ignore_obj_list = NULL; fq.flags = 0; find_vector_intersection( &fq, &hit_data); if (hit_data.hit_type == HIT_NONE) { *camera_pos = closer_p1; } else { make_random_vector(&player_camera_vec); far_scale = 3*F1_0/2; } } } } extern void drop_player_eggs(object *playerobj); extern int get_explosion_vclip(object *obj,int stage); // ------------------------------------------------------------------------------------------------------------------ void dead_player_frame(void) { static fix time_dead = 0; vms_vector fvec; if (Player_is_dead) { time_dead += FrameTime; // If unable to create camera at time of death, create now. if (Dead_player_camera == Viewer_save) { int objnum; object *player = &Objects[Players[Player_num].objnum]; objnum = obj_create(OBJ_CAMERA, 0, player->segnum, &player->pos, &player->orient, 0, CT_NONE, MT_NONE, RT_NONE); if (objnum != -1) Viewer = Dead_player_camera = &Objects[objnum]; else { Int3(); } } ConsoleObject->mtype.phys_info.rotvel.x = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/4; ConsoleObject->mtype.phys_info.rotvel.y = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/2; ConsoleObject->mtype.phys_info.rotvel.z = max(0, DEATH_SEQUENCE_EXPLODE_TIME - time_dead)/3; Camera_to_player_dist_goal = min(time_dead*8, F1_0*20) + ConsoleObject->size; set_camera_pos(&Dead_player_camera->pos, ConsoleObject); // the following line uncommented by WraithX, 4-12-00 if (time_dead < DEATH_SEQUENCE_EXPLODE_TIME+F1_0*2) { vm_vec_sub(&fvec, &ConsoleObject->pos, &Dead_player_camera->pos); vm_vector_2_matrix(&Dead_player_camera->orient, &fvec, NULL, NULL); Dead_player_camera->mtype.phys_info = ConsoleObject->mtype.phys_info; // the following "if" added by WraithX to get rid of camera "wiggle" if (Dead_player_camera->mtype.phys_info.flags & PF_WIGGLE) { Dead_player_camera->mtype.phys_info.flags = (Dead_player_camera->mtype.phys_info.flags & ~PF_WIGGLE); }// end "if" added by WraithX, 4/13/00 // the following line uncommented by WraithX, 4-12-00 } else { // the following line uncommented by WraithX, 4-11-00 Dead_player_camera->movement_type = MT_PHYSICS; //Dead_player_camera->mtype.phys_info.rotvel.y = F1_0/8; // the following line uncommented by WraithX, 4-12-00 } // end addition by WX if (time_dead > DEATH_SEQUENCE_EXPLODE_TIME) { if (!Player_exploded) { if (Players[Player_num].hostages_on_board > 1) HUD_init_message(HM_DEFAULT, TXT_SHIP_DESTROYED_2, Players[Player_num].hostages_on_board); else if (Players[Player_num].hostages_on_board == 1) HUD_init_message_literal(HM_DEFAULT, TXT_SHIP_DESTROYED_1); else HUD_init_message_literal(HM_DEFAULT, TXT_SHIP_DESTROYED_0); Players[Player_num].hostages_on_board = 0; Player_exploded = 1; #ifdef NETWORK if (Game_mode & GM_NETWORK) multi_powcap_cap_objects(); #endif drop_player_eggs(ConsoleObject); Player_eggs_dropped = 1; #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_player_explode(MULTI_PLAYER_EXPLODE); } #endif explode_badass_player(ConsoleObject); //is this next line needed, given the badass call above? explode_object(ConsoleObject,0); ConsoleObject->flags &= ~OF_SHOULD_BE_DEAD; //don't really kill player ConsoleObject->render_type = RT_NONE; //..just make him disappear ConsoleObject->type = OBJ_GHOST; //..and kill intersections } } else { if (d_rand() < FrameTime*4) { #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_create_explosion(Player_num); #endif create_small_fireball_on_object(ConsoleObject, F1_0, 1); } } if (Death_sequence_aborted) { if (!Player_eggs_dropped) { #ifdef NETWORK if (Game_mode & GM_NETWORK) multi_powcap_cap_objects(); #endif drop_player_eggs(ConsoleObject); Player_eggs_dropped = 1; #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_player_explode(MULTI_PLAYER_EXPLODE); } #endif } DoPlayerDead(); //kill_player(); } } else time_dead = 0; } // ------------------------------------------------------------------------------------------------------------------ void start_player_death_sequence(object *player) { int objnum; Assert(player == ConsoleObject); if ((Player_is_dead != 0) || (Dead_player_camera != NULL)) return; //Assert(Player_is_dead == 0); //Assert(Dead_player_camera == NULL); reset_rear_view(); if (!(Game_mode & GM_MULTI)) HUD_clear_messages(); Death_sequence_aborted = 0; #ifdef NETWORK if (Game_mode & GM_MULTI) { multi_send_kill(Players[Player_num].objnum); } #endif PaletteRedAdd = 40; Player_is_dead = 1; vm_vec_zero(&player->mtype.phys_info.rotthrust); //this line commented by WraithX vm_vec_zero(&player->mtype.phys_info.thrust); objnum = obj_create(OBJ_CAMERA, 0, player->segnum, &player->pos, &player->orient, 0, CT_NONE, MT_NONE, RT_NONE); Viewer_save = Viewer; if (objnum != -1) Viewer = Dead_player_camera = &Objects[objnum]; else { Int3(); Dead_player_camera = Viewer; } select_cockpit(CM_LETTERBOX); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_letterbox(); Player_flags_save = player->flags; Control_type_save = player->control_type; Render_type_save = player->render_type; player->flags &= ~OF_SHOULD_BE_DEAD; // Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE; player->control_type = CT_NONE; player->shields = F1_0*1000; PALETTE_FLASH_SET(0,0,0); } // ------------------------------------------------------------------------------------------------------------------ void obj_delete_all_that_should_be_dead() { int i; object *objp; int local_dead_player_object=-1; // Move all objects objp = Objects; for (i=0;i<=Highest_object_index;i++) { if ((objp->type!=OBJ_NONE) && (objp->flags&OF_SHOULD_BE_DEAD) ) { Assert(!(objp->type==OBJ_FIREBALL && objp->ctype.expl_info.delete_time!=-1)); if (objp->type==OBJ_PLAYER) { if ( objp->id == Player_num ) { if (local_dead_player_object == -1) { start_player_death_sequence(objp); local_dead_player_object = objp-Objects; } else Int3(); // Contact Mike: Illegal, killed player twice in this frame! // Ok to continue, won't start death sequence again! // kill_player(); } } else { obj_delete(i); } } objp++; } } //when an object has moved into a new segment, this function unlinks it //from its old segment, and links it into the new segment void obj_relink(int objnum,int newsegnum) { Assert((objnum >= 0) && (objnum <= Highest_object_index)); Assert((newsegnum <= Highest_segment_index) && (newsegnum >= 0)); obj_unlink(objnum); obj_link(objnum,newsegnum); } // for getting out of messed up linking situations (i.e. caused by demo playback) void obj_relink_all(void) { int segnum; int objnum; object *obj; for (segnum=0; segnum <= Highest_segment_index; segnum++) Segments[segnum].objects = -1; for (objnum=0,obj=&Objects[0];objnum<=Highest_object_index;objnum++,obj++) if (obj->type != OBJ_NONE) { segnum = obj->segnum; obj->next = obj->prev = obj->segnum = -1; if (segnum > Highest_segment_index) segnum = 0; obj_link(objnum, segnum); } } //process a continuously-spinning object void spin_object(object *obj) { vms_angvec rotangs; vms_matrix rotmat, new_pm; Assert(obj->movement_type == MT_SPINNING); rotangs.p = fixmul(obj->mtype.spin_rate.x,FrameTime); rotangs.h = fixmul(obj->mtype.spin_rate.y,FrameTime); rotangs.b = fixmul(obj->mtype.spin_rate.z,FrameTime); vm_angles_2_matrix(&rotmat,&rotangs); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; check_and_fix_matrix(&obj->orient); } //-------------------------------------------------------------------- //move an object for the current frame void object_move_one( object * obj ) { #ifndef DEMO_ONLY int previous_segment = obj->segnum; obj->last_pos = obj->pos; // Save the current position if ((obj->type==OBJ_PLAYER) && (Player_num==obj->id)) { fix fuel; fuel=fuelcen_give_fuel( &Segments[obj->segnum], i2f(100)-Players[Player_num].energy ); if (fuel > 0 ) { Players[Player_num].energy += fuel; } } if (obj->lifeleft != IMMORTAL_TIME) //if not immortal... obj->lifeleft -= FrameTime; //...inevitable countdown towards death switch (obj->control_type) { case CT_NONE: break; case CT_FLYING: read_flying_controls( obj ); break; case CT_REPAIRCEN: Int3(); // -- hey! these are no longer supported!! -- do_repair_sequence(obj); break; case CT_POWERUP: do_powerup_frame(obj); break; case CT_MORPH: //morph implies AI do_morph_frame(obj); //NOTE: FALLS INTO AI HERE!!!! case CT_AI: //NOTE LINK TO CT_MORPH ABOVE!!! if (Game_suspended & SUSP_ROBOTS) return; do_ai_frame(obj); break; case CT_WEAPON: Laser_do_weapon_sequence(obj); break; case CT_EXPLOSION: do_explosion_sequence(obj); break; #ifndef RELEASE case CT_SLEW: if ( keyd_pressed[KEY_PAD5] ) slew_stop( obj ); if ( keyd_pressed[KEY_NUMLOCK] ) { slew_reset_orient( obj ); } slew_frame(0 ); // Does velocity addition for us. break; #endif // case CT_FLYTHROUGH: // do_flythrough(obj,0); // HACK:do_flythrough should operate on an object!!!! // //check_object_seg(obj); // return; // DON'T DO THE REST OF OBJECT STUFF SINCE THIS IS A SPECIAL CASE!!! // break; case CT_DEBRIS: do_debris_frame(obj); break; case CT_LIGHT: break; //doesn't do anything case CT_REMOTE: break; //doesn't do anything case CT_CNTRLCEN: do_controlcen_frame(obj); break; default: Error("Unknown control type %d in object %d, sig/type/id = %d/%d/%d",obj->control_type,(int) (obj-Objects), obj->signature, obj->type, obj->id); break; } if (obj->lifeleft < 0 ) { // We died of old age obj->flags |= OF_SHOULD_BE_DEAD; if ( obj->type==OBJ_WEAPON && Weapon_info[obj->id].damage_radius ) explode_badass_weapon(obj); } if (obj->type == OBJ_NONE || obj->flags&OF_SHOULD_BE_DEAD) return; // object has been deleted switch (obj->movement_type) { case MT_NONE: break; //this doesn't move case MT_PHYSICS: do_physics_sim(obj); break; //move by physics case MT_SPINNING: spin_object(obj); break; } // If player and moved to another segment, see if hit any triggers. if (obj->type == OBJ_PLAYER && obj->movement_type==MT_PHYSICS) { if (previous_segment != obj->segnum) { int connect_side,i; for (i=0;i MAX_USED_OBJECTS) free_object_slots(MAX_USED_OBJECTS); // Free all possible object slots. obj_delete_all_that_should_be_dead(); if (PlayerCfg.AutoLeveling) ConsoleObject->mtype.phys_info.flags |= PF_LEVELLING; else ConsoleObject->mtype.phys_info.flags &= ~PF_LEVELLING; // Move all objects objp = Objects; #ifndef DEMO_ONLY for (i=0;i<=Highest_object_index;i++) { if ( (objp->type != OBJ_NONE) && (!(objp->flags&OF_SHOULD_BE_DEAD)) ) { object_move_one( objp ); } objp++; } #else i=0; //kill warning #endif // check_duplicate_objects(); // remove_incorrect_objects(); } //--unused-- // ----------------------------------------------------------- //--unused-- // Moved here from eobject.c on 02/09/94 by MK. //--unused-- int find_last_obj(int i) //--unused-- { //--unused-- for (i=MAX_OBJECTS;--i>=0;) //--unused-- if (Objects[i].type != OBJ_NONE) break; //--unused-- //--unused-- return i; //--unused-- //--unused-- } //make object array non-sparse void compress_objects(void) { int start_i; //,last_i; //last_i = find_last_obj(MAX_OBJECTS); // Note: It's proper to do < (rather than <=) Highest_object_index here because we // are just removing gaps, and the last object can't be a gap. for (start_i=0;start_i0); for (i=num_objects;ipos,obj->segnum); } //If an object is in a segment, set its segnum field and make sure it's //properly linked. If not in any segment, returns 0, else 1. //callers should generally use find_vector_intersection() int update_object_seg(object * obj ) { int newseg; newseg = find_object_seg(obj); if (newseg == -1) return 0; if ( newseg != obj->segnum ) obj_relink(obj-Objects, newseg ); return 1; } //go through all objects and make sure they have the correct segment numbers void fix_object_segs() { int i; for (i=0;i<=Highest_object_index;i++) if (Objects[i].type != OBJ_NONE) if (update_object_seg(&Objects[i]) == 0) { Int3(); compute_segment_center(&Objects[i].pos,&Segments[Objects[i].segnum]); } } //--unused-- void object_use_new_object_list( object * new_list ) //--unused-- { //--unused-- int i, segnum; //--unused-- object *obj; //--unused-- //--unused-- // First, unlink all the old objects for the segments array //--unused-- for (segnum=0; segnum <= Highest_segment_index; segnum++) { //--unused-- Segments[segnum].objects = -1; //--unused-- } //--unused-- // Then, erase all the objects //--unused-- reset_objects(1); //--unused-- //--unused-- // Fill in the object array //--unused-- memcpy( Objects, new_list, sizeof(object)*MAX_OBJECTS ); //--unused-- //--unused-- Highest_object_index=-1; //--unused-- //--unused-- // Relink 'em //--unused-- for (i=0; itype != OBJ_NONE ) { //--unused-- num_objects++; //--unused-- Highest_object_index = i; //--unused-- segnum = obj->segnum; //--unused-- obj->next = obj->prev = obj->segnum = -1; //--unused-- obj_link(i,segnum); //--unused-- } else { //--unused-- obj->next = obj->prev = obj->segnum = -1; //--unused-- } //--unused-- } //--unused-- //--unused-- } //delete objects, such as weapons & explosions, that shouldn't stay between levels // Changed by MK on 10/15/94, don't remove proximity bombs. //if clear_all is set, clear even proximity bombs void clear_transient_objects(int clear_all) { int objnum; object *obj; for (objnum=0,obj=&Objects[0];objnum<=Highest_object_index;objnum++,obj++) if (((obj->type == OBJ_WEAPON) && (clear_all || !is_proximity_bomb_or_smart_mine(obj->id))) || obj->type == OBJ_FIREBALL || obj->type == OBJ_DEBRIS || obj->type == OBJ_DEBRIS || (obj->type!=OBJ_NONE && obj->flags & OF_EXPLODING)) { obj_delete(objnum); } } //attaches an object, such as a fireball, to another object, such as a robot void obj_attach(object *parent,object *sub) { Assert(sub->type == OBJ_FIREBALL); Assert(sub->control_type == CT_EXPLOSION); Assert(sub->ctype.expl_info.next_attach==-1); Assert(sub->ctype.expl_info.prev_attach==-1); Assert(parent->attached_obj==-1 || Objects[parent->attached_obj].ctype.expl_info.prev_attach==-1); sub->ctype.expl_info.next_attach = parent->attached_obj; if (sub->ctype.expl_info.next_attach != -1) Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach = sub-Objects; parent->attached_obj = sub-Objects; sub->ctype.expl_info.attach_parent = parent-Objects; sub->flags |= OF_ATTACHED; Assert(sub->ctype.expl_info.next_attach != sub-Objects); Assert(sub->ctype.expl_info.prev_attach != sub-Objects); } //dettaches one object void obj_detach_one(object *sub) { Assert(sub->flags & OF_ATTACHED); Assert(sub->ctype.expl_info.attach_parent != -1); if ((Objects[sub->ctype.expl_info.attach_parent].type == OBJ_NONE) || (Objects[sub->ctype.expl_info.attach_parent].attached_obj == -1)) { sub->flags &= ~OF_ATTACHED; return; } if (sub->ctype.expl_info.next_attach != -1) { Assert(Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach=sub-Objects); Objects[sub->ctype.expl_info.next_attach].ctype.expl_info.prev_attach = sub->ctype.expl_info.prev_attach; } if (sub->ctype.expl_info.prev_attach != -1) { Assert(Objects[sub->ctype.expl_info.prev_attach].ctype.expl_info.next_attach=sub-Objects); Objects[sub->ctype.expl_info.prev_attach].ctype.expl_info.next_attach = sub->ctype.expl_info.next_attach; } else { Assert(Objects[sub->ctype.expl_info.attach_parent].attached_obj=sub-Objects); Objects[sub->ctype.expl_info.attach_parent].attached_obj = sub->ctype.expl_info.next_attach; } sub->ctype.expl_info.next_attach = sub->ctype.expl_info.prev_attach = -1; sub->flags &= ~OF_ATTACHED; } //dettaches all objects from this object void obj_detach_all(object *parent) { while (parent->attached_obj != -1) obj_detach_one(&Objects[parent->attached_obj]); } // Swap endianess of given object_rw if swap == 1 void object_rw_swap(object_rw *obj, int swap) { if (!swap) return; obj->signature = SWAPINT(obj->signature); obj->next = SWAPSHORT(obj->next); obj->prev = SWAPSHORT(obj->prev); obj->segnum = SWAPSHORT(obj->segnum); obj->attached_obj = SWAPSHORT(obj->attached_obj); obj->pos.x = SWAPINT(obj->pos.x); obj->pos.y = SWAPINT(obj->pos.y); obj->pos.z = SWAPINT(obj->pos.z); obj->orient.rvec.x = SWAPINT(obj->orient.rvec.x); obj->orient.rvec.y = SWAPINT(obj->orient.rvec.y); obj->orient.rvec.z = SWAPINT(obj->orient.rvec.z); obj->orient.fvec.x = SWAPINT(obj->orient.fvec.x); obj->orient.fvec.y = SWAPINT(obj->orient.fvec.y); obj->orient.fvec.z = SWAPINT(obj->orient.fvec.z); obj->orient.uvec.x = SWAPINT(obj->orient.uvec.x); obj->orient.uvec.y = SWAPINT(obj->orient.uvec.y); obj->orient.uvec.z = SWAPINT(obj->orient.uvec.z); obj->size = SWAPINT(obj->size); obj->shields = SWAPINT(obj->shields); obj->last_pos.x = SWAPINT(obj->last_pos.x); obj->last_pos.y = SWAPINT(obj->last_pos.y); obj->last_pos.z = SWAPINT(obj->last_pos.z); obj->lifeleft = SWAPINT(obj->lifeleft); switch (obj->movement_type) { case MT_PHYSICS: obj->mtype.phys_info.velocity.x = SWAPINT(obj->mtype.phys_info.velocity.x); obj->mtype.phys_info.velocity.y = SWAPINT(obj->mtype.phys_info.velocity.y); obj->mtype.phys_info.velocity.z = SWAPINT(obj->mtype.phys_info.velocity.z); obj->mtype.phys_info.thrust.x = SWAPINT(obj->mtype.phys_info.thrust.x); obj->mtype.phys_info.thrust.y = SWAPINT(obj->mtype.phys_info.thrust.y); obj->mtype.phys_info.thrust.z = SWAPINT(obj->mtype.phys_info.thrust.z); obj->mtype.phys_info.mass = SWAPINT(obj->mtype.phys_info.mass); obj->mtype.phys_info.drag = SWAPINT(obj->mtype.phys_info.drag); obj->mtype.phys_info.brakes = SWAPINT(obj->mtype.phys_info.brakes); obj->mtype.phys_info.rotvel.x = SWAPINT(obj->mtype.phys_info.rotvel.x); obj->mtype.phys_info.rotvel.y = SWAPINT(obj->mtype.phys_info.rotvel.y); obj->mtype.phys_info.rotvel.z = SWAPINT(obj->mtype.phys_info.rotvel.z); obj->mtype.phys_info.rotthrust.x = SWAPINT(obj->mtype.phys_info.rotthrust.x); obj->mtype.phys_info.rotthrust.y = SWAPINT(obj->mtype.phys_info.rotthrust.y); obj->mtype.phys_info.rotthrust.z = SWAPINT(obj->mtype.phys_info.rotthrust.z); obj->mtype.phys_info.turnroll = SWAPINT(obj->mtype.phys_info.turnroll); obj->mtype.phys_info.flags = SWAPSHORT(obj->mtype.phys_info.flags); break; case MT_SPINNING: obj->mtype.spin_rate.x = SWAPINT(obj->mtype.spin_rate.x); obj->mtype.spin_rate.y = SWAPINT(obj->mtype.spin_rate.y); obj->mtype.spin_rate.z = SWAPINT(obj->mtype.spin_rate.z); break; } switch (obj->control_type) { case CT_WEAPON: obj->ctype.laser_info.parent_type = SWAPSHORT(obj->ctype.laser_info.parent_type); obj->ctype.laser_info.parent_num = SWAPSHORT(obj->ctype.laser_info.parent_num); obj->ctype.laser_info.parent_signature = SWAPINT(obj->ctype.laser_info.parent_signature); obj->ctype.laser_info.creation_time = SWAPINT(obj->ctype.laser_info.creation_time); obj->ctype.laser_info.last_hitobj = SWAPSHORT(obj->ctype.laser_info.last_hitobj); obj->ctype.laser_info.track_goal = SWAPSHORT(obj->ctype.laser_info.track_goal); obj->ctype.laser_info.multiplier = SWAPINT(obj->ctype.laser_info.multiplier); break; case CT_EXPLOSION: obj->ctype.expl_info.spawn_time = SWAPINT(obj->ctype.expl_info.spawn_time); obj->ctype.expl_info.delete_time = SWAPINT(obj->ctype.expl_info.delete_time); obj->ctype.expl_info.delete_objnum = SWAPSHORT(obj->ctype.expl_info.delete_objnum); obj->ctype.expl_info.attach_parent = SWAPSHORT(obj->ctype.expl_info.attach_parent); obj->ctype.expl_info.prev_attach = SWAPSHORT(obj->ctype.expl_info.prev_attach); obj->ctype.expl_info.next_attach = SWAPSHORT(obj->ctype.expl_info.next_attach); break; case CT_AI: obj->ctype.ai_info.hide_segment = SWAPSHORT(obj->ctype.ai_info.hide_segment); obj->ctype.ai_info.hide_index = SWAPSHORT(obj->ctype.ai_info.hide_index); obj->ctype.ai_info.path_length = SWAPSHORT(obj->ctype.ai_info.path_length); obj->ctype.ai_info.cur_path_index = SWAPSHORT(obj->ctype.ai_info.cur_path_index); obj->ctype.ai_info.follow_path_start_seg = SWAPSHORT(obj->ctype.ai_info.follow_path_start_seg); obj->ctype.ai_info.follow_path_end_seg = SWAPSHORT(obj->ctype.ai_info.follow_path_end_seg); obj->ctype.ai_info.danger_laser_signature = SWAPINT(obj->ctype.ai_info.danger_laser_signature); obj->ctype.ai_info.danger_laser_num = SWAPSHORT(obj->ctype.ai_info.danger_laser_num); break; case CT_LIGHT: obj->ctype.light_info.intensity = SWAPINT(obj->ctype.light_info.intensity); break; case CT_POWERUP: obj->ctype.powerup_info.count = SWAPINT(obj->ctype.powerup_info.count); break; } switch (obj->render_type) { case RT_MORPH: case RT_POLYOBJ: case RT_NONE: // HACK below { int i; if (obj->render_type == RT_NONE && obj->type != OBJ_GHOST) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. break; obj->rtype.pobj_info.model_num = SWAPINT(obj->rtype.pobj_info.model_num); for (i=0;irtype.pobj_info.anim_angles[i].p = SWAPINT(obj->rtype.pobj_info.anim_angles[i].p); obj->rtype.pobj_info.anim_angles[i].b = SWAPINT(obj->rtype.pobj_info.anim_angles[i].b); obj->rtype.pobj_info.anim_angles[i].h = SWAPINT(obj->rtype.pobj_info.anim_angles[i].h); } obj->rtype.pobj_info.subobj_flags = SWAPINT(obj->rtype.pobj_info.subobj_flags); obj->rtype.pobj_info.tmap_override = SWAPINT(obj->rtype.pobj_info.tmap_override); obj->rtype.pobj_info.alt_textures = SWAPINT(obj->rtype.pobj_info.alt_textures); break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj->rtype.vclip_info.vclip_num = SWAPINT(obj->rtype.vclip_info.vclip_num); obj->rtype.vclip_info.frametime = SWAPINT(obj->rtype.vclip_info.frametime); break; case RT_LASER: break; } } dxx-rebirth-0.58.1-d1x/main/object.h000066400000000000000000000507771217717257200171350ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * object system definitions * */ #ifndef _OBJECT_H #define _OBJECT_H #include "pstypes.h" #include "vecmat.h" #include "segment.h" #include "gameseg.h" #include "aistruct.h" #include "gr.h" #include "piggy.h" /* * CONSTANTS */ #define MAX_OBJECTS 350 // increased on 01/24/95 for multiplayer. --MK; total number of objects in world #define MAX_USED_OBJECTS (MAX_OBJECTS-20) // Object types enum object_type_t { OBJ_NONE = 255, // unused object OBJ_WALL = 0, // A wall... not really an object, but used for collisions OBJ_FIREBALL = 1, // a fireball, part of an explosion OBJ_ROBOT = 2, // an evil enemy OBJ_HOSTAGE = 3, // a hostage you need to rescue OBJ_PLAYER = 4, // the player on the console OBJ_WEAPON = 5, // a laser, missile, etc OBJ_CAMERA = 6, // a camera to slew around with OBJ_POWERUP = 7, // a powerup you can pick up OBJ_DEBRIS = 8, // a piece of robot OBJ_CNTRLCEN = 9, // the control center OBJ_FLARE = 10, // a flare OBJ_CLUTTER = 11, // misc objects OBJ_GHOST = 12, // what the player turns into when dead OBJ_LIGHT = 13, // a light source, & not much else OBJ_COOP = 14, // a cooperative player object. }; // WARNING!! If you add a type here, add its name to Object_type_names // in object.c #define MAX_OBJECT_TYPES 15 // Result types #define RESULT_NOTHING 0 // Ignore this collision #define RESULT_CHECK 1 // Check for this collision // Control types - what tells this object what do do #define CT_NONE 0 // doesn't move (or change movement) #define CT_AI 1 // driven by AI #define CT_EXPLOSION 2 // explosion sequencer #define CT_FLYING 4 // the player is flying #define CT_SLEW 5 // slewing #define CT_FLYTHROUGH 6 // the flythrough system #define CT_WEAPON 9 // laser, etc. #define CT_REPAIRCEN 10 // under the control of the repair center #define CT_MORPH 11 // this object is being morphed #define CT_DEBRIS 12 // this is a piece of debris #define CT_POWERUP 13 // animating powerup blob #define CT_LIGHT 14 // doesn't actually do anything #define CT_REMOTE 15 // controlled by another net player #define CT_CNTRLCEN 16 // the control center/main reactor // Movement types #define MT_NONE 0 // doesn't move #define MT_PHYSICS 1 // moves by physics #define MT_SPINNING 3 // this object doesn't move, just sits and spins // Render types #define RT_NONE 0 // does not render #define RT_POLYOBJ 1 // a polygon model #define RT_FIREBALL 2 // a fireball #define RT_LASER 3 // a laser #define RT_HOSTAGE 4 // a hostage #define RT_POWERUP 5 // a powerup #define RT_MORPH 6 // a robot being morphed #define RT_WEAPON_VCLIP 7 // a weapon that renders as a vclip // misc object flags #define OF_EXPLODING 1 // this object is exploding #define OF_SHOULD_BE_DEAD 2 // this object should be dead, so next time we can, we should delete this object. #define OF_DESTROYED 4 // this has been killed, and is showing the dead version #define OF_SILENT 8 // this makes no sound when it hits a wall. Added by MK for weapons, if you extend it to other types, do it completely! #define OF_ATTACHED 16 // this object is a fireball attached to another object #define OF_HARMLESS 32 // this object does no damage. Added to make quad lasers do 1.5 damage as normal lasers. // Different Weapon ID types... #define WEAPON_ID_LASER 0 #define WEAPON_ID_MISSLE 1 #define WEAPON_ID_CANNONBALL 2 // Object Initial shields... #define OBJECT_INITIAL_SHIELDS F1_0/2 // physics flags #define PF_TURNROLL 0x01 // roll when turning #define PF_LEVELLING 0x02 // level object with closest side #define PF_BOUNCE 0x04 // bounce (not slide) when hit will #define PF_WIGGLE 0x08 // wiggle while flying #define PF_STICK 0x10 // object sticks (stops moving) when hits wall #define PF_PERSISTENT 0x20 // object keeps going even after it hits another object (eg, fusion cannon) #define PF_USES_THRUST 0x40 // this object uses its thrust #define IMMORTAL_TIME 0x3fffffff // Time assigned to immortal objects, about 32768 seconds, or about 9 hours. extern char Object_type_names[MAX_OBJECT_TYPES][9]; // List of objects rendered last frame in order. Created at render // time, used by homing missiles in laser.c #define MAX_RENDERED_OBJECTS 50 extern short Ordered_rendered_object_list[MAX_RENDERED_OBJECTS]; extern int Num_rendered_objects; /* * STRUCTURES */ #define MAX_CONTROLCEN_GUNS 4 struct reactor_static { /* Location of the gun on the reactor object */ vms_vector gun_pos[MAX_CONTROLCEN_GUNS]; /* Orientation of the gun on the reactor object */ vms_vector gun_dir[MAX_CONTROLCEN_GUNS]; }; // A compressed form for sending crucial data typedef struct shortpos { sbyte bytemat[9]; short xo,yo,zo; short segment; short velx, vely, velz; } __pack__ shortpos; // Another compressed form for object position, velocity, orientation and rotvel using quaternion typedef struct quaternionpos { vms_quaternion orient; vms_vector pos; vms_vector vel; vms_vector rotvel; } __pack__ quaternionpos; // This is specific to the shortpos extraction routines in gameseg.c. #define RELPOS_PRECISION 10 #define MATRIX_PRECISION 9 #define MATRIX_MAX 0x7f // This is based on MATRIX_PRECISION, 9 => 0x7f // information for physics sim for an object typedef struct physics_info { vms_vector velocity; // velocity vector of this object vms_vector thrust; // constant force applied to this object fix mass; // the mass of this object fix drag; // how fast this slows down fix brakes; // how much brakes applied vms_vector rotvel; // rotational velecity (angles) vms_vector rotthrust; // rotational acceleration fixang turnroll; // rotation caused by turn banking ushort flags; // misc physics flags } __pack__ physics_info; // stuctures for different kinds of simulation typedef struct laser_info { short parent_type; // The type of the parent of this object short parent_num; // The object's parent's number int parent_signature; // The object's parent's signature... fix64 creation_time; // Absolute time of creation. short last_hitobj; // For persistent weapons (survive object collision), object it most recently hit. ubyte hitobj_list[MAX_OBJECTS]; // list of all objects persistent weapon has already damaged (useful in case it's in contact with two objects at the same time) short track_goal; // Object this object is tracking. fix multiplier; // Power if this is a fusion bolt (or other super weapon to be added). } __pack__ laser_info; // Same as above but structure Savegames/Multiplayer objects expect typedef struct laser_info_rw { short parent_type; // The type of the parent of this object short parent_num; // The object's parent's number int parent_signature; // The object's parent's signature... fix creation_time; // Absolute time of creation. short last_hitobj; // For persistent weapons (survive object collision), object it most recently hit. short track_goal; // Object this object is tracking. fix multiplier; // Power if this is a fusion bolt (or other super weapon to be added). } __pack__ laser_info_rw; extern ubyte hitobj_list[MAX_OBJECTS][MAX_OBJECTS]; typedef struct explosion_info { fix spawn_time; // when lifeleft is < this, spawn another fix delete_time; // when to delete object short delete_objnum; // and what object to delete short attach_parent; // explosion is attached to this object short prev_attach; // previous explosion in attach list short next_attach; // next explosion in attach list } __pack__ explosion_info; typedef struct light_info { fix intensity; // how bright the light is } __pack__ light_info; typedef struct powerup_info { int count; // how many/much we pick up (vulcan cannon only?) } __pack__ powerup_info; typedef struct vclip_info { int vclip_num; fix frametime; sbyte framenum; } __pack__ vclip_info; // structures for different kinds of rendering typedef struct polyobj_info { int model_num; // which polygon model vms_angvec anim_angles[MAX_SUBMODELS]; // angles for each subobject int subobj_flags; // specify which subobjs to draw int tmap_override; // if this is not -1, map all face to this int alt_textures; // if not -1, use these textures instead } __pack__ polyobj_info; typedef struct object { int signature; // Every object ever has a unique signature... ubyte type; // what type of object this is... robot, weapon, hostage, powerup, fireball ubyte id; // which form of object...which powerup, robot, etc. #ifdef WORDS_NEED_ALIGNMENT short pad; #endif short next,prev; // id of next and previous connected object in Objects, -1 = no connection ubyte control_type; // how this object is controlled ubyte movement_type; // how this object moves ubyte render_type; // how this object renders ubyte flags; // misc flags short segnum; // segment number containing object short attached_obj; // number of attached fireball object vms_vector pos; // absolute x,y,z coordinate of center of object vms_matrix orient; // orientation of object in world fix size; // 3d size of object - for collision detection fix shields; // Starts at maximum, when <0, object dies.. vms_vector last_pos; // where object was last frame sbyte contains_type; // Type of object this object contains (eg, spider contains powerup) sbyte contains_id; // ID of object this object contains (eg, id = blue type = key) sbyte contains_count; // number of objects of type:id this object contains sbyte matcen_creator; // Materialization center that created this object, high bit set if matcen-created fix lifeleft; // how long until goes away, or 7fff if immortal // -- Removed, MK, 10/16/95, using lifeleft instead: int lightlevel; // movement info, determined by MOVEMENT_TYPE union { physics_info phys_info; // a physics object vms_vector spin_rate; // for spinning objects } __pack__ mtype; // control info, determined by CONTROL_TYPE union { struct laser_info laser_info; struct explosion_info expl_info; // NOTE: debris uses this also struct ai_static ai_info; struct light_info light_info; // why put this here? Didn't know what else to do with it. struct powerup_info powerup_info; struct reactor_static reactor_info; } __pack__ ctype ; // render info, determined by RENDER_TYPE union { struct polyobj_info pobj_info; // polygon model struct vclip_info vclip_info; // vclip } __pack__ rtype ; #ifdef WORDS_NEED_ALIGNMENT short pad2; #endif } __pack__ object; // Same as above but structure Savegames/Multiplayer objects expect typedef struct object_rw { int signature; // Every object ever has a unique signature... ubyte type; // what type of object this is... robot, weapon, hostage, powerup, fireball ubyte id; // which form of object...which powerup, robot, etc. #ifdef WORDS_NEED_ALIGNMENT short pad; #endif short next,prev; // id of next and previous connected object in Objects, -1 = no connection ubyte control_type; // how this object is controlled ubyte movement_type; // how this object moves ubyte render_type; // how this object renders ubyte flags; // misc flags short segnum; // segment number containing object short attached_obj; // number of attached fireball object vms_vector pos; // absolute x,y,z coordinate of center of object vms_matrix orient; // orientation of object in world fix size; // 3d size of object - for collision detection fix shields; // Starts at maximum, when <0, object dies.. vms_vector last_pos; // where object was last frame sbyte contains_type; // Type of object this object contains (eg, spider contains powerup) sbyte contains_id; // ID of object this object contains (eg, id = blue type = key) sbyte contains_count; // number of objects of type:id this object contains sbyte matcen_creator; // Materialization center that created this object, high bit set if matcen-created fix lifeleft; // how long until goes away, or 7fff if immortal // -- Removed, MK, 10/16/95, using lifeleft instead: int lightlevel; // movement info, determined by MOVEMENT_TYPE union { physics_info phys_info; // a physics object vms_vector spin_rate; // for spinning objects } __pack__ mtype ; // control info, determined by CONTROL_TYPE union { struct laser_info_rw laser_info; struct explosion_info expl_info; // NOTE: debris uses this also struct ai_static ai_info; struct light_info light_info; // why put this here? Didn't know what else to do with it. struct powerup_info powerup_info; } __pack__ ctype ; // render info, determined by RENDER_TYPE union { struct polyobj_info pobj_info; // polygon model struct vclip_info vclip_info; // vclip } __pack__ rtype; #ifdef WORDS_NEED_ALIGNMENT short pad2; #endif } __pack__ object_rw; typedef struct obj_position { vms_vector pos; // absolute x,y,z coordinate of center of object vms_matrix orient; // orientation of object in world short segnum; // segment number containing object } obj_position; /* * VARIABLES */ extern int Object_next_signature; // The next signature for the next newly created object extern ubyte CollisionResult[MAX_OBJECT_TYPES][MAX_OBJECT_TYPES]; // ie CollisionResult[a][b]== what happens to a when it collides with b extern object Objects[]; extern int Highest_object_index; // highest objnum extern int num_objects; extern char *robot_names[]; // name of each robot extern int Num_robot_types; extern object *ConsoleObject; // pointer to the object that is the player extern object *Viewer; // which object we are seeing from extern object *Dead_player_camera; extern object Follow; extern int Player_is_dead; // !0 means player is dead! extern int Player_exploded; extern int Player_eggs_dropped; extern int Death_sequence_aborted; extern int Player_fired_laser_this_frame; /* * FUNCTIONS */ // do whatever setup needs to be done void init_objects(); // returns segment number object is in. Searches out from object's current // seg, so this shouldn't be called if the object has "jumped" to a new seg int obj_get_new_seg(object *obj); // when an object has moved into a new segment, this function unlinks it // from its old segment, and links it into the new segment void obj_relink(int objnum,int newsegnum); // for getting out of messed up linking situations (i.e. caused by demo playback) void obj_relink_all(void); // move an object from one segment to another. unlinks & relinks void obj_set_new_seg(int objnum,int newsegnum); // links an object into a segment's list of objects. // takes object number and segment number void obj_link(int objnum,int segnum); // unlinks an object from a segment's list of objects void obj_unlink(int objnum); // initialize a new object. adds to the list for the given segment // returns the object number int obj_create(enum object_type_t type, ubyte id, int segnum, vms_vector *pos, vms_matrix *orient, fix size, ubyte ctype, ubyte mtype, ubyte rtype); // make a copy of an object. returs num of new object int obj_create_copy(int objnum, vms_vector *new_pos, int newsegnum); // remove object from the world void obj_delete(int objnum); // called after load. Takes number of objects, and objects should be // compressed void reset_objects(int n_objs); // make object array non-sparse void compress_objects(void); // Render an object. Calls one of several routines based on type void render_object(object *obj); // Draw a blob-type object, like a fireball void draw_object_blob(object *obj, bitmap_index bitmap); // draw an object that is a texture-mapped rod void draw_object_tmap_rod(object *obj, bitmap_index bitmap, int lighted); // Deletes all objects that have been marked for death. void obj_delete_all_that_should_be_dead(); // Toggles whether or not lock-boxes draw. void object_toggle_lock_targets(); // move all objects for the current frame void object_move_all(); // moves all objects // set viewer object to next object in array void object_goto_next_viewer(); // draw target boxes for nearby robots void object_render_targets(void); // move an object for the current frame void object_move_one(object * obj); // make object0 the player, setting all relevant fields void init_player_object(); // check if object is in object->segnum. if not, check the adjacent // segs. if not any of these, returns false, else sets obj->segnum & // returns true callers should really use find_vector_intersection() // Note: this function is in gameseg.c extern int update_object_seg(struct object *obj); // Finds what segment *obj is in, returns segment number. If not in // any segment, returns -1. Note: This function is defined in // gameseg.h, but object.h depends on gameseg.h, and object.h is where // object is defined...get it? extern int find_object_seg(object * obj ); // go through all objects and make sure they have the correct segment // numbers used when debugging is on void fix_object_segs(); // Drops objects contained in objp. int object_create_egg(object *objp); // Interface to object_create_egg, puts count objects of type type, id // = id in objp and then drops them. int call_object_create_egg(object *objp, int count, int type, int id); extern void dead_player_end(void); // Extract information from an object (objp->orient, objp->pos, // objp->segnum), stuff in a shortpos structure. See typedef // shortpos. extern void create_shortpos(shortpos *spp, object *objp, int swap_bytes); // Extract information from a shortpos, stuff in objp->orient // (matrix), objp->pos, objp->segnum extern void extract_shortpos(object *objp, shortpos *spp, int swap_bytes); // create and extract quaternion structure from object data which greatly saves bytes by using quaternion instead or orientation matrix void create_quaternionpos(quaternionpos * qpp, object * objp, int swap_bytes); void extract_quaternionpos(object *objp, quaternionpos *qpp, int swap_bytes); // delete objects, such as weapons & explosions, that shouldn't stay // between levels if clear_all is set, clear even proximity bombs void clear_transient_objects(int clear_all); // Returns a new, unique signature for a new object int obj_get_signature(); // returns the number of a free object, updating Highest_object_index. // Generally, obj_create() should be called to get an object, since it // fills in important fields and does the linking. returns -1 if no // free objects int obj_allocate(void); // frees up an object. Generally, obj_delete() should be called to // get rid of an object. This function deallocates the object entry // after the object has been unlinked void obj_free(int objnum); // after calling init_object(), the network code has grabbed specific // object slots without allocating them. Go though the objects & // build the free list, then set the apporpriate globals Don't call // this function if you don't know what you're doing. void special_reset_objects(void); // attaches an object, such as a fireball, to another object, such as // a robot void obj_attach(object *parent,object *sub); extern void create_small_fireball_on_object(object *objp, fix size_scale, int sound_flag); extern void object_rw_swap(object_rw *obj_rw, int swap); #endif dxx-rebirth-0.58.1-d1x/main/paging.c000066400000000000000000000201211217717257200171030ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for paging in/out textures. * */ #include #include #include #include #include "inferno.h" #include "segment.h" #include "textures.h" #include "wall.h" #include "object.h" #include "gamemine.h" #include "dxxerror.h" #include "gameseg.h" #include "game.h" #include "piggy.h" #include "texmerge.h" #include "polyobj.h" #include "vclip.h" #include "effects.h" #include "fireball.h" #include "weapon.h" #include "palette.h" #include "timer.h" #include "text.h" #include "cntrlcen.h" #include "gauges.h" #include "powerup.h" #include "fuelcen.h" void paging_touch_vclip( vclip * vc ) { int i; for (i=0; inum_frames; i++ ) { PIGGY_PAGE_IN( vc->frames[i] ); } } void paging_touch_wall_effects( int tmap_num ) { int i; for (i=0;i -1) PIGGY_PAGE_IN( Textures[Effects[i].dest_bm_num] ); //use this bitmap when monitor destroyed if ( Effects[i].dest_vclip > -1 ) paging_touch_vclip( &Vclip[Effects[i].dest_vclip] ); //what vclip to play when exploding if ( Effects[i].dest_eclip > -1 ) paging_touch_vclip( &Effects[Effects[i].dest_eclip].vc ); //what eclip to play when exploding if ( Effects[i].crit_clip > -1 ) paging_touch_vclip( &Effects[Effects[i].crit_clip].vc ); //what eclip to play when mine critical } } } void paging_touch_object_effects( int tmap_num ) { int i; for (i=0;in_textures;i++) { PIGGY_PAGE_IN( ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]] ); paging_touch_object_effects( ObjBitmapPtrs[pm->first_texture+i] ); //paging_touch_object_effects( pm->first_texture+i ); } } void paging_touch_weapon( int weapon_type ) { // Page in the robot's weapons. if ( (weapon_type < 0) || (weapon_type > N_weapon_types) ) return; if ( Weapon_info[weapon_type].picture.index ) { PIGGY_PAGE_IN( Weapon_info[weapon_type].picture ); } if ( Weapon_info[weapon_type].flash_vclip > -1 ) paging_touch_vclip(&Vclip[Weapon_info[weapon_type].flash_vclip]); if ( Weapon_info[weapon_type].wall_hit_vclip > -1 ) paging_touch_vclip(&Vclip[Weapon_info[weapon_type].wall_hit_vclip]); if ( Weapon_info[weapon_type].damage_radius ) { // Robot_hit_vclips are actually badass_vclips if ( Weapon_info[weapon_type].robot_hit_vclip > -1 ) paging_touch_vclip(&Vclip[Weapon_info[weapon_type].robot_hit_vclip]); } switch( Weapon_info[weapon_type].render_type ) { case WEAPON_RENDER_VCLIP: if ( Weapon_info[weapon_type].weapon_vclip > -1 ) paging_touch_vclip( &Vclip[Weapon_info[weapon_type].weapon_vclip] ); break; case WEAPON_RENDER_NONE: break; case WEAPON_RENDER_POLYMODEL: paging_touch_model( Weapon_info[weapon_type].model_num ); break; case WEAPON_RENDER_BLOB: PIGGY_PAGE_IN( Weapon_info[weapon_type].bitmap ); break; } } sbyte super_boss_gate_type_list[13] = {0, 1, 8, 9, 10, 11, 12, 15, 16, 18, 19, 20, 22 }; void paging_touch_robot( int robot_index ) { int i; // Page in robot_index paging_touch_model(Robot_info[robot_index].model_num); if ( Robot_info[robot_index].exp1_vclip_num>-1 ) paging_touch_vclip(&Vclip[Robot_info[robot_index].exp1_vclip_num]); if ( Robot_info[robot_index].exp2_vclip_num>-1 ) paging_touch_vclip(&Vclip[Robot_info[robot_index].exp2_vclip_num]); // Page in his weapons paging_touch_weapon( Robot_info[robot_index].weapon_type ); // A super-boss can gate in robots... if ( Robot_info[robot_index].boss_flag==2 ) { for (i=0; i<13; i++ ) paging_touch_robot(super_boss_gate_type_list[i]); paging_touch_vclip( &Vclip[VCLIP_MORPHING_ROBOT] ); } } void paging_touch_object( object * obj ) { int v; switch (obj->render_type) { case RT_NONE: break; //doesn't render, like the player case RT_POLYOBJ: if ( obj->rtype.pobj_info.tmap_override != -1 ) PIGGY_PAGE_IN( Textures[obj->rtype.pobj_info.tmap_override] ); else paging_touch_model(obj->rtype.pobj_info.model_num); break; case RT_POWERUP: if ( obj->rtype.vclip_info.vclip_num > -1 ) paging_touch_vclip(&Vclip[obj->rtype.vclip_info.vclip_num]); break; case RT_MORPH: break; case RT_FIREBALL: break; case RT_WEAPON_VCLIP: break; case RT_HOSTAGE: paging_touch_vclip(&Vclip[obj->rtype.vclip_info.vclip_num]); break; case RT_LASER: break; } switch (obj->type) { case OBJ_PLAYER: v = get_explosion_vclip(obj, 0); if ( v > -1 ) paging_touch_vclip(&Vclip[v]); break; case OBJ_ROBOT: paging_touch_robot( obj->id ); break; case OBJ_CNTRLCEN: paging_touch_weapon( CONTROLCEN_WEAPON_NUM ); if (Dead_modelnums[obj->rtype.pobj_info.model_num] != -1) { paging_touch_model( Dead_modelnums[obj->rtype.pobj_info.model_num] ); } break; } } void paging_touch_side( segment * segp, int sidenum ) { int tmap1, tmap2; if (!(WALL_IS_DOORWAY(segp,sidenum) & WID_RENDER_FLAG)) return; tmap1 = segp->sides[sidenum].tmap_num; paging_touch_wall_effects(tmap1); tmap2 = segp->sides[sidenum].tmap_num2; if (tmap2 != 0) { texmerge_get_cached_bitmap( tmap1, tmap2 ); paging_touch_wall_effects( tmap2 & 0x3FFF ); } else { PIGGY_PAGE_IN( Textures[tmap1] ); } } void paging_touch_robot_maker( segment * segp ) { if ( segp->special == SEGMENT_IS_ROBOTMAKER ) { paging_touch_vclip(&Vclip[VCLIP_MORPHING_ROBOT]); if (RobotCenters[segp->matcen_num].robot_flags[0] != 0) { uint flags; int robot_index; robot_index = 0; flags = RobotCenters[segp->matcen_num].robot_flags[0]; while (flags) { if (flags & 1) { // Page in robot_index paging_touch_robot( robot_index ); } flags >>= 1; robot_index++; } } } } void paging_touch_segment(segment * segp) { int sn; int objnum; if ( segp->special == SEGMENT_IS_ROBOTMAKER ) paging_touch_robot_maker(segp); // paging_draw_orb(); for (sn=0;snobjects;objnum!=-1;objnum=Objects[objnum].next) { // paging_draw_orb(); paging_touch_object( &Objects[objnum] ); } } void paging_touch_walls() { int i,j; wclip *anim; for (i=0;i -1 ) { anim = &WallAnims[Walls[i].clip_num]; for (j=0; j < anim->num_frames; j++ ) { PIGGY_PAGE_IN( Textures[anim->frames[j]] ); } } } } void paging_touch_all() { int s; stop_time(); show_boxed_message(TXT_LOADING, 0); for (s=0; s<=Highest_segment_index; s++) { paging_touch_segment( &Segments[s] ); } paging_touch_walls(); for ( s=0; s < N_powerup_types; s++ ) { if ( Powerup_info[s].vclip_num > -1 ) paging_touch_vclip(&Vclip[Powerup_info[s].vclip_num]); } for ( s=0; s -1 ) paging_touch_vclip(&Vclip[Powerup_info[s].vclip_num]); } for (s=0; s #include #include "joy.h" #include "dxxerror.h" #include "inferno.h" #include "segment.h" #include "object.h" #include "physics.h" #include "key.h" #include "game.h" #include "collide.h" #include "fvi.h" #include "newdemo.h" #include "timer.h" #include "ai.h" #include "wall.h" #include "laser.h" //Global variables for physics system #define ROLL_RATE 0x2000 #define DAMP_ANG 0x400 //min angle to bank #define TURNROLL_SCALE (0x4ec4/2) //check point against each side of segment. return bitmask, where bit //set means behind that side int floor_levelling=0; //make sure matrix is orthogonal void check_and_fix_matrix(vms_matrix *m) { vms_matrix tempm; vm_vector_2_matrix(&tempm,&m->fvec,&m->uvec,NULL); *m = tempm; } void do_physics_align_object( object * obj ) { vms_vector desired_upvec; fixang delta_ang,roll_ang; //vms_vector forvec = {0,0,f1_0}; vms_matrix temp_matrix; fix d,largest_d=-f1_0; int i,best_side; best_side=0; // bank player according to segment orientation //find side of segment that player is most alligned with for (i=0;i<6;i++) { #ifdef COMPACT_SEGS vms_vector _tv1; get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 ); d = vm_vec_dot(&_tv1,&obj->orient.uvec); #else d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec); #endif if (d > largest_d) {largest_d = d; best_side=i;} } if (floor_levelling) { // old way: used floor's normal as upvec #ifdef COMPACT_SEGS get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec ); #else desired_upvec = Segments[obj->segnum].sides[3].normals[0]; #endif } else // new player leveling code: use normal of side closest to our up vec if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) { #ifdef COMPACT_SEGS vms_vector normals[2]; get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] ); desired_upvec.x = (normals[0].x + normals[1].x) / 2; desired_upvec.y = (normals[0].y + normals[1].y) / 2; desired_upvec.z = (normals[0].z + normals[1].z) / 2; vm_vec_normalize(&desired_upvec); #else side *s = &Segments[obj->segnum].sides[best_side]; desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2; desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2; desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2; vm_vec_normalize(&desired_upvec); #endif } else #ifdef COMPACT_SEGS get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec ); #else desired_upvec = Segments[obj->segnum].sides[best_side].normals[0]; #endif if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) { vms_angvec tangles; vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL); delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec); delta_ang += obj->mtype.phys_info.turnroll; if (abs(delta_ang) > DAMP_ANG) { vms_matrix rotmat, new_pm; roll_ang = fixmul(FrameTime,ROLL_RATE); if (abs(delta_ang) < roll_ang) roll_ang = delta_ang; else if (delta_ang<0) roll_ang = -roll_ang; tangles.p = tangles.h = 0; tangles.b = roll_ang; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } else floor_levelling=0; } } void set_object_turnroll(object *obj) { fixang desired_bank; desired_bank = -fixmul(obj->mtype.phys_info.rotvel.y,TURNROLL_SCALE); if (obj->mtype.phys_info.turnroll != desired_bank) { fixang delta_ang,max_roll; max_roll = fixmul(ROLL_RATE,FrameTime); delta_ang = desired_bank - obj->mtype.phys_info.turnroll; if (labs(delta_ang) < max_roll) max_roll = delta_ang; else if (delta_ang < 0) max_roll = -max_roll; obj->mtype.phys_info.turnroll += max_roll; } } //list of segments went through int phys_seglist[MAX_FVI_SEGS],n_phys_segs; #define MAX_IGNORE_OBJS 100 #ifndef NDEBUG #define EXTRA_DEBUG 1 //no extra debug when NDEBUG is on #endif #ifdef EXTRA_DEBUG object *debug_obj=NULL; #endif #ifndef NDEBUG int Total_retries=0, Total_sims=0; int Dont_move_ai_objects=0; #endif #define FT (f1_0/64) // ----------------------------------------------------------------------------------------------------------- // add rotational velocity & acceleration void do_physics_sim_rot(object *obj) { vms_angvec tangles; vms_matrix rotmat,new_orient; //fix rotdrag_scale; physics_info *pi; Assert(FrameTime > 0); //Get MATT if hit this! pi = &obj->mtype.phys_info; if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z)) return; if (obj->mtype.phys_info.drag) { int count; vms_vector accel; fix drag,r,k; count = FrameTime / FT; r = FrameTime % FT; k = fixdiv(r,FT); drag = (obj->mtype.phys_info.drag*5)/2; if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); while (count--) { vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel); vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k); vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag)); } else { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag); } } //now rotate object //unrotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = -obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime); tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime); tangles.b = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime); vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat); obj->orient = new_orient; if (obj->mtype.phys_info.flags & PF_TURNROLL) set_object_turnroll(obj); //re-rotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } check_and_fix_matrix(&obj->orient); } // On joining edges fvi tends to get inaccurate as hell. Approach is to check if the object interects with the wall and if so, move away from it. void fix_illegal_wall_intersection(object *obj, vms_vector *origin) { int hseg = -1, hside = -1, hface = -1; if (!(obj->type == OBJ_PLAYER || obj->type == OBJ_ROBOT)) return; if ( object_intersects_wall_d(obj,&hseg,&hside,&hface) ) { vm_vec_scale_add2(&obj->pos,&Segments[hseg].sides[hside].normals[0],FrameTime*10); update_object_seg(obj); } } // ----------------------------------------------------------------------------------------------------------- //Simulate a physics object for this frame void do_physics_sim(object *obj) { int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs; int iseg; int try_again; int fate=0; vms_vector frame_vec; //movement in this frame vms_vector new_pos,ipos; //position after this frame int count=0; int objnum; int WallHitSeg, WallHitSide; fvi_info hit_info; fvi_query fq; vms_vector save_pos; int save_seg; fix drag; fix sim_time; vms_vector start_pos; int obj_stopped=0; fix moved_time; //how long objected moved before hit something physics_info *pi; int orig_segnum = obj->segnum; int bounced=0; fix PhysTime = (FrameTimemovement_type == MT_PHYSICS); #ifndef NDEBUG if (Dont_move_ai_objects) if (obj->control_type == CT_AI) return; #endif pi = &obj->mtype.phys_info; do_physics_sim_rot(obj); if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z)) return; objnum = obj-Objects; n_phys_segs = 0; /* As this engine was not designed for that high FPS as we intend, we use F1_0/30 max. for sim_time to ensure scaling and dot products stay accurate and reliable. The object position intended for this frame will be scaled down later, after the main collision-loop is done. This won't make collision results be equal in all FPS settings, but hopefully more accurate, the higher our FPS are. */ sim_time = PhysTime; //FrameTime; //debug_obj = obj; #ifdef EXTRA_DEBUG //check for correct object segment if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0) { if (!update_object_seg(obj)) { if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } #endif start_pos = obj->pos; n_ignore_objs = 0; Assert(obj->mtype.phys_info.brakes==0); //brakes not used anymore? //if uses thrust, cannot have zero drag Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0); //do thrust & drag // NOTE: this always must be dependent on FrameTime, if sim_time differs! if ((drag = obj->mtype.phys_info.drag) != 0) { int count; vms_vector accel; fix r,k,have_accel; count = FrameTime / FT; r = FrameTime % FT; k = fixdiv(r,FT); if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); have_accel = (accel.x || accel.y || accel.z); while (count--) { if (have_accel) vm_vec_add2(&obj->mtype.phys_info.velocity,&accel); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k); if (drag) vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag)); } else if (drag) { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag); } } do { try_again = 0; //Move the object vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time); if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) break; count++; // If retry count is getting large, then we are trying to do something stupid. if (count > 8) break; // in original code this was 3 for all non-player objects. still leave us some limit in case fvi goes apeshit. vm_vec_add(&new_pos,&obj->pos,&frame_vec); ignore_obj_list[n_ignore_objs] = -1; fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = &new_pos; fq.rad = obj->size; fq.thisobjnum = objnum; fq.ignore_obj_list = ignore_obj_list; fq.flags = FQ_CHECK_OBJS; if (obj->type == OBJ_WEAPON) fq.flags |= FQ_TRANSPOINT; if (obj->type == OBJ_PLAYER) fq.flags |= FQ_GET_SEGLIST; fate = find_vector_intersection(&fq,&hit_info); // Matt: Mike's hack. if (fate == HIT_OBJECT) { object *objp = &Objects[hit_info.hit_object]; if (((objp->type == OBJ_WEAPON) && is_proximity_bomb_or_smart_mine(objp->id)) || objp->type == OBJ_POWERUP) // do not increase count for powerups since they *should* not change our movement count--; } #ifndef NDEBUG if (fate == HIT_BAD_P0) { Int3(); } #endif if (obj->type == OBJ_PLAYER) { int i; if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0]) n_phys_segs--; for (i=0;(itype == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; break; } Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index)))); save_pos = obj->pos; //save the object's position save_seg = obj->segnum; // update object's position and segment number obj->pos = ipos; if ( iseg != obj->segnum ) obj_relink(objnum, iseg ); //if start point not in segment, move object to center of segment if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask !=0 ) { int n; if ((n=find_object_seg(obj))==-1) { //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } return; } //calulate new sim time { //vms_vector moved_vec; vms_vector moved_vec_n; fix attempted_dist,actual_dist; actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos); if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) { //moved backwards //don't change position or sim_time obj->pos = save_pos; //iseg = obj->segnum; //don't change segment obj_relink(objnum, save_seg ); moved_time = 0; } else { fix old_sim_time; attempted_dist = vm_vec_mag(&frame_vec); old_sim_time = sim_time; sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist); moved_time = old_sim_time - sim_time; if (sim_time < 0 || sim_time>old_sim_time) { sim_time = old_sim_time; //WHY DOES THIS HAPPEN?? moved_time = 0; } } } switch( fate ) { case HIT_WALL: { vms_vector moved_v; fix hit_speed=0,wall_part=0; // Find hit speed vm_vec_sub(&moved_v,&obj->pos,&save_pos); wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm); if ((wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) || obj->type == OBJ_WEAPON || obj->type == OBJ_DEBRIS) collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); if (obj->type == OBJ_PLAYER) scrape_player_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); Assert( WallHitSeg > -1 ); Assert( WallHitSide > -1 ); if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { int forcefield_bounce; //bounce off a forcefield Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE)); //can't be bounce and stick /* * Force fields are not supported in Descent 1. Use * this as a placeholder to make the code match the * force field handling in Descent 2. */ forcefield_bounce = 0; if (!forcefield_bounce && (obj->mtype.phys_info.flags & PF_STICK)) { //stop moving add_stuck_object(obj, WallHitSeg, WallHitSide); vm_vec_zero(&obj->mtype.phys_info.velocity); obj_stopped = 1; try_again = 0; } else { // Slide object along wall //We're constrained by wall, so subtract wall part from //velocity vector wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity); // if wall_part, make sure the value is sane enough to get usable velocity computed if (wall_part < 0 && wall_part > -f1_0) wall_part = -f1_0; if (wall_part > 0 && wall_part < f1_0) wall_part = f1_0; if (forcefield_bounce || (obj->mtype.phys_info.flags & PF_BOUNCE)) { //bounce off wall wall_part *= 2; //Subtract out wall part twice to achieve bounce } vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part); try_again = 1; } } break; } case HIT_OBJECT: { vms_vector old_vel; // Mark the hit object so that on a retry the fvi code // ignores this object. Assert(hit_info.hit_object != -1); // Calculcate the hit point between the two objects. { vms_vector *ppos0, *ppos1, pos_hit; fix size0, size1; ppos0 = &Objects[hit_info.hit_object].pos; ppos1 = &obj->pos; size0 = Objects[hit_info.hit_object].size; size1 = obj->size; Assert(size0+size1 != 0); // Error, both sizes are 0, so how did they collide, anyway?!? //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1)); //vm_vec_add2(&pos_hit, ppos0); vm_vec_sub(&pos_hit, ppos1, ppos0); vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1)); old_vel = obj->mtype.phys_info.velocity; collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit); } // Let object continue its movement if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { //obj->pos = save_pos; if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) { //if (Objects[hit_info.hit_object].type == OBJ_POWERUP) ignore_obj_list[n_ignore_objs++] = hit_info.hit_object; try_again = 1; } } break; } case HIT_NONE: break; #ifndef NDEBUG case HIT_BAD_P0: Int3(); // Unexpected collision type: start point not in specified segment. break; default: // Unknown collision type returned from find_vector_intersection!! Int3(); break; #endif } } while ( try_again ); // Pass retry count info to AI. if (obj->control_type == CT_AI) { if (count > 0) { Ai_local_info[objnum].retry_count = count-1; #ifndef NDEBUG Total_retries += count-1; Total_sims++; #endif } } // As sim_time may not base on FrameTime, scale actual object position to get accurate movement if (PhysTime/FrameTime > 0) { vms_vector md; vm_vec_sub(&md, &obj->pos, &start_pos); vm_vec_scale(&md, F1_0/((float)PhysTime/FrameTime)); vm_vec_add(&obj->pos,&start_pos, &md); //check for and update correct object segment if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0) { if (!update_object_seg(obj)) { if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } } // After collision with objects and walls, set velocity from actual movement if (!obj_stopped && !bounced && ((obj->type == OBJ_PLAYER) || (obj->type == OBJ_ROBOT) || (obj->type == OBJ_DEBRIS)) && ((fate == HIT_WALL) || (fate == HIT_OBJECT) || (fate == HIT_BAD_P0)) ) { vms_vector moved_vec; vm_vec_sub(&moved_vec,&obj->pos,&start_pos); vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime)); } fix_illegal_wall_intersection(obj, &start_pos); //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0); //if (obj->control_type == CT_FLYING) if (obj->mtype.phys_info.flags & PF_LEVELLING) do_physics_align_object( obj ); //hack to keep player from going through closed doors if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (!cheats.ghostphysics) ) { int sidenum; sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]); if (sidenum != -1) { if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) { side *s; int vertnum,num_faces,i; fix dist; int vertex_list[6]; //bump object back s = &Segments[orig_segnum].sides[sidenum]; create_abs_vertex_lists(&num_faces, vertex_list, orig_segnum, sidenum, __FILE__, __LINE__); //let's pretend this wall is not triangulated vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS { vms_vector _vn; get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn ); dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist); } #else dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist); #endif update_object_seg(obj); } } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG //if end point not in segment, move object to last pos, or segment center if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask != 0) { if (find_object_seg(obj)==-1) { int n; //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif } //Applies an instantaneous force on an object, resulting in an instantaneous //change in velocity. void phys_apply_force(object *obj,vms_vector *force_vec) { if (obj->movement_type != MT_PHYSICS) return; //Add in acceleration due to force vm_vec_scale_add2(&obj->mtype.phys_info.velocity,force_vec,fixdiv(f1_0,obj->mtype.phys_info.mass)); } // ---------------------------------------------------------------- // Do *dest = *delta unless: // *delta is pretty small // and they are of different signs. void physics_set_rotvel_and_saturate(fix *dest, fix delta) { if ((delta ^ *dest) < 0) { if (abs(delta) < F1_0/8) { *dest = delta/4; } else *dest = delta; } else { *dest = delta; } } // ------------------------------------------------------------------------------------------------------ // Note: This is the old ai_turn_towards_vector code. // phys_apply_rot used to call ai_turn_towards_vector until I fixed it, which broke phys_apply_rot. void physics_turn_towards_vector(vms_vector *goal_vector, object *obj, fix rate) { vms_angvec dest_angles, cur_angles; fix delta_p, delta_h; vms_vector *rotvel_ptr = &obj->mtype.phys_info.rotvel; // Make this object turn towards the goal_vector. Changes orientation, doesn't change direction of movement. // If no one moves, will be facing goal_vector in 1 second. // Detect null vector. if ((goal_vector->x == 0) && (goal_vector->y == 0) && (goal_vector->z == 0)) return; // Make morph objects turn more slowly. if (obj->control_type == CT_MORPH) rate *= 2; vm_extract_angles_vector(&dest_angles, goal_vector); vm_extract_angles_vector(&cur_angles, &obj->orient.fvec); delta_p = (dest_angles.p - cur_angles.p); delta_h = (dest_angles.h - cur_angles.h); if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0; if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0; if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0; if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0; delta_p = fixdiv(delta_p, rate); delta_h = fixdiv(delta_h, rate); if (abs(delta_p) < F1_0/16) delta_p *= 4; if (abs(delta_h) < F1_0/16) delta_h *= 4; #ifdef WORDS_NEED_ALIGNMENT if ((delta_p ^ rotvel_ptr->x) < 0) { if (abs(delta_p) < F1_0/8) rotvel_ptr->x = delta_p/4; else rotvel_ptr->x = delta_p; } else rotvel_ptr->x = delta_p; if ((delta_h ^ rotvel_ptr->y) < 0) { if (abs(delta_h) < F1_0/8) rotvel_ptr->y = delta_h/4; else rotvel_ptr->y = delta_h; } else rotvel_ptr->y = delta_h; #else physics_set_rotvel_and_saturate(&rotvel_ptr->x, delta_p); physics_set_rotvel_and_saturate(&rotvel_ptr->y, delta_h); #endif rotvel_ptr->z = 0; } // ----------------------------------------------------------------------------- // Applies an instantaneous whack on an object, resulting in an instantaneous // change in orientation. void phys_apply_rot(object *obj,vms_vector *force_vec) { fix rate, vecmag; if (obj->movement_type != MT_PHYSICS) return; vecmag = vm_vec_mag(force_vec)/8; if (vecmag < F1_0/256) rate = 4*F1_0; else if (vecmag < obj->mtype.phys_info.mass >> 14) rate = 4*F1_0; else { rate = fixdiv(obj->mtype.phys_info.mass, vecmag); if (obj->type == OBJ_ROBOT) { if (rate < F1_0/4) rate = F1_0/4; obj->ctype.ai_info.SKIP_AI_COUNT = 2; } else { if (rate < F1_0/2) rate = F1_0/2; } } // Turn amount inversely proportional to mass. Third parameter is seconds to do 360 turn. physics_turn_towards_vector(force_vec, obj, rate); } //this routine will set the thrust for an object to a value that will //(hopefully) maintain the object's current velocity void set_thrust_from_velocity(object *obj) { fix k; Assert(obj->movement_type == MT_PHYSICS); k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag)); vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->mtype.phys_info.velocity,k); } dxx-rebirth-0.58.1-d1x/main/physics.h000066400000000000000000000041701217717257200173330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Headers for physics functions and data * */ #ifndef _PHYSICS_H #define _PHYSICS_H #include "vecmat.h" #include "fvi.h" //#define FL_NORMAL 0 //#define FL_TURBO 1 //#define FL_HOVER 2 //#define FL_REVERSE 3 // these global vars are set after a call to do_physics_sim(). Ugly, I know. // list of segments went through extern int phys_seglist[MAX_FVI_SEGS], n_phys_segs; // Read contrls and set physics vars void read_flying_controls(object *obj); // Simulate a physics object for this frame void do_physics_sim(object *obj); // tell us what the given object will do (as far as hiting walls) in // the given time (in seconds) t. Igores acceleration (sorry) // if check_objects is set, check with objects, else just with walls // returns fate, fills in hit time. If fate==HIT_NONE, hit_time undefined // Stuff hit_info with fvi data as set by find_vector_intersection. // for fvi_flags, refer to fvi.h for the fvi query flags int physics_lookahead(object *obj, fix t, int fvi_flags, fix *hit_time, fvi_info *hit_info); // Applies an instantaneous force on an object, resulting in an instantaneous // change in velocity. void phys_apply_force(object *obj, vms_vector *force_vec); void phys_apply_rot(object *obj, vms_vector *force_vec); // this routine will set the thrust for an object to a value that will // (hopefully) maintain the object's current velocity void set_thrust_from_velocity(object *obj); #endif dxx-rebirth-0.58.1-d1x/main/piggy.c000066400000000000000000000646041217717257200167730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for managing the pig files. * */ #include #include #include #include #include "pstypes.h" #include "inferno.h" #include "gr.h" #include "u_mem.h" #include "dxxerror.h" #include "sounds.h" #include "bm.h" #include "hash.h" #include "args.h" #include "palette.h" #include "gamefont.h" #include "rle.h" #include "screens.h" #include "snddecom.h" #include "console.h" #include "piggy.h" #include "texmerge.h" #include "paging.h" #include "game.h" #include "text.h" #include "newmenu.h" #include "custom.h" int piggy_is_substitutable_bitmap( char * name, char * subst_name ); //#define NO_DUMP_SOUNDS 1 //if set, dump bitmaps but not sounds ubyte *BitmapBits = NULL; ubyte *SoundBits = NULL; typedef struct BitmapFile { char name[15]; } BitmapFile; typedef struct SoundFile { char name[15]; } SoundFile; hashtable AllBitmapsNames; hashtable AllDigiSndNames; int Num_bitmap_files = 0; int Num_sound_files = 0; digi_sound GameSounds[MAX_SOUND_FILES]; int SoundOffset[MAX_SOUND_FILES]; grs_bitmap GameBitmaps[MAX_BITMAP_FILES]; int Num_bitmap_files_new = 0; int Num_sound_files_new = 0; static BitmapFile AllBitmaps[ MAX_BITMAP_FILES ]; static SoundFile AllSounds[ MAX_SOUND_FILES ]; #define DBM_FLAG_LARGE 128 // Flags added onto the flags struct in b #define DBM_FLAG_ABM 64 int Piggy_bitmap_cache_size = 0; int Piggy_bitmap_cache_next = 0; ubyte * Piggy_bitmap_cache_data = NULL; /*static*/ int GameBitmapOffset[MAX_BITMAP_FILES]; /*static*/ ubyte GameBitmapFlags[MAX_BITMAP_FILES]; ushort GameBitmapXlat[MAX_BITMAP_FILES]; #define DEFAULT_PIGFILE_REGISTERED "descent.pig" #define PIGGY_BUFFER_SIZE (2048*1024) #define PIGGY_SMALL_BUFFER_SIZE (1400*1024) // size of buffer when GameArg.SysLowMem is set int piggy_page_flushed = 0; typedef struct DiskBitmapHeader { char name[8]; ubyte dflags; ubyte width; ubyte height; ubyte flags; ubyte avg_color; int offset; } __pack__ DiskBitmapHeader; typedef struct DiskSoundHeader { char name[8]; int length; int data_length; int offset; } __pack__ DiskSoundHeader; /* * reads a DiskBitmapHeader structure from a PHYSFS_file */ void DiskBitmapHeader_read(DiskBitmapHeader *dbh, PHYSFS_file *fp) { PHYSFS_read(fp, dbh->name, 8, 1); dbh->dflags = PHYSFSX_readByte(fp); dbh->width = PHYSFSX_readByte(fp); dbh->height = PHYSFSX_readByte(fp); dbh->flags = PHYSFSX_readByte(fp); dbh->avg_color = PHYSFSX_readByte(fp); dbh->offset = PHYSFSX_readInt(fp); } /* * reads a DiskSoundHeader structure from a PHYSFS_file */ void DiskSoundHeader_read(DiskSoundHeader *dsh, PHYSFS_file *fp) { PHYSFS_read(fp, dsh->name, 8, 1); dsh->length = PHYSFSX_readInt(fp); dsh->data_length = PHYSFSX_readInt(fp); dsh->offset = PHYSFSX_readInt(fp); } static int SoundCompressed[ MAX_SOUND_FILES ]; void swap_0_255(grs_bitmap *bmp) { int i; for (i = 0; i < bmp->bm_h * bmp->bm_w; i++) { if(bmp->bm_data[i] == 0) bmp->bm_data[i] = 255; else if (bmp->bm_data[i] == 255) bmp->bm_data[i] = 0; } } void piggy_get_bitmap_name( int i, char * name ) { strncpy( name, AllBitmaps[i].name, 12 ); name[12] = 0; } bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file ) { bitmap_index temp; Assert( Num_bitmap_files < MAX_BITMAP_FILES ); temp.index = Num_bitmap_files; if (!in_file) { if ( !GameArg.DbgBigPig ) gr_bitmap_rle_compress( bmp ); Num_bitmap_files_new++; } strncpy( AllBitmaps[Num_bitmap_files].name, name, 12 ); hashtable_insert( &AllBitmapsNames, AllBitmaps[Num_bitmap_files].name, Num_bitmap_files ); GameBitmaps[Num_bitmap_files] = *bmp; if ( !in_file ) { GameBitmapOffset[Num_bitmap_files] = 0; GameBitmapFlags[Num_bitmap_files] = bmp->bm_flags; } Num_bitmap_files++; return temp; } int piggy_register_sound( digi_sound * snd, char * name, int in_file ) { int i; Assert( Num_sound_files < MAX_SOUND_FILES ); strncpy( AllSounds[Num_sound_files].name, name, 12 ); hashtable_insert( &AllDigiSndNames, AllSounds[Num_sound_files].name, Num_sound_files ); GameSounds[Num_sound_files] = *snd; //added/moved on 11/13/99 by Victor Rachels to ready for changing freq //#ifdef ALLEGRO GameSounds[Num_sound_files].bits = snd->bits; GameSounds[Num_sound_files].freq = snd->freq; #ifdef ALLEGRO //end this section move - VR GameSounds[Num_sound_files].priority = 128; GameSounds[Num_sound_files].loop_start = 0; GameSounds[Num_sound_files].loop_end = GameSounds[Num_sound_files].len; GameSounds[Num_sound_files].param = -1; #endif if ( !in_file ) { SoundOffset[Num_sound_files] = 0; } else if (SoundOffset[Num_sound_files] == 0) SoundOffset[Num_sound_files] = -1; // make sure this sound's data is not individually freed i = Num_sound_files; if (!in_file) Num_sound_files_new++; Num_sound_files++; return i; } bitmap_index piggy_find_bitmap( char * name ) { bitmap_index bmp; int i; bmp.index = 0; i = hashtable_search( &AllBitmapsNames, name ); Assert( i != 0 ); if ( i < 0 ) return bmp; bmp.index = i; return bmp; } int piggy_find_sound( char * name ) { int i; i = hashtable_search( &AllDigiSndNames, name ); if ( i < 0 ) return 255; return i; } PHYSFS_file * Piggy_fp = NULL; void piggy_close_file() { if ( Piggy_fp ) { PHYSFS_close( Piggy_fp ); Piggy_fp = NULL; } } ubyte bogus_data[64*64]; grs_bitmap bogus_bitmap; ubyte bogus_bitmap_initialized=0; digi_sound bogus_sound; int MacPig = 0; // using the Macintosh pigfile? int PCSharePig = 0; // using PC Shareware pigfile? extern void properties_read_cmp(PHYSFS_file * fp); #ifdef EDITOR extern void bm_write_all(PHYSFS_file * fp); #endif int properties_init() { int sbytes = 0; char temp_name_read[16]; char temp_name[16]; grs_bitmap temp_bitmap; digi_sound temp_sound; DiskBitmapHeader bmh; DiskSoundHeader sndh; int header_size, N_bitmaps, N_sounds; int i,size; int Pigdata_start; int pigsize; int retval; hashtable_init( &AllBitmapsNames, MAX_BITMAP_FILES ); hashtable_init( &AllDigiSndNames, MAX_SOUND_FILES ); for (i=0; i 0 ); #else Piggy_bitmap_cache_size = PIGGY_BUFFER_SIZE; if (GameArg.SysLowMem) Piggy_bitmap_cache_size = PIGGY_SMALL_BUFFER_SIZE; #endif BitmapBits = d_malloc( Piggy_bitmap_cache_size ); if ( BitmapBits == NULL ) Error( "Not enough memory to load DESCENT.PIG bitmaps\n" ); Piggy_bitmap_cache_data = BitmapBits; Piggy_bitmap_cache_next = 0; return retval; } int piggy_is_needed(int soundnum) { int i; if ( !GameArg.SysLowMem ) return 1; for (i=0; i 0 ) { if ( piggy_is_needed(i) ) { PHYSFSX_fseek( Piggy_fp, SoundOffset[i], SEEK_SET ); // Read in the sound data!!! snd->data = ptr; #ifdef ALLEGRO ptr += snd->len; sbytes += snd->len; #else ptr += snd->length; sbytes += snd->length; #endif //Arne's decompress for shareware on all soundcards - Tim@Rikers.org if (pc_shareware) { if (lastsize < SoundCompressed[i]) { if (lastbuf) d_free(lastbuf); lastbuf = d_malloc(SoundCompressed[i]); } PHYSFS_read( Piggy_fp, lastbuf, SoundCompressed[i], 1 ); sound_decompress( lastbuf, SoundCompressed[i], snd->data ); } else #ifdef ALLEGRO PHYSFS_read( Piggy_fp, snd->data, snd->len, 1 ); #else PHYSFS_read( Piggy_fp, snd->data, snd->length, 1 ); #endif } } } if (lastbuf) d_free(lastbuf); } extern int descent_critical_error; extern unsigned descent_critical_deverror; extern unsigned descent_critical_errcode; char * crit_errors[13] = { "Write Protected", "Unknown Unit", "Drive Not Ready", "Unknown Command", "CRC Error", "Bad struct length", "Seek Error", "Unknown media type", "Sector not found", "Printer out of paper", "Write Fault", "Read fault", "General Failure" }; void piggy_critical_error() { grs_canvas * save_canv; grs_font * save_font; int i; save_canv = grd_curcanv; save_font = grd_curcanv->cv_font; gr_palette_load( gr_palette ); i = nm_messagebox( "Disk Error", 2, "Retry", "Exit", "%s\non drive %c:", crit_errors[descent_critical_errcode&0xf], (descent_critical_deverror&0xf)+'A' ); if ( i == 1 ) exit(1); gr_set_current_canvas(save_canv); grd_curcanv->cv_font = save_font; } void piggy_bitmap_page_in( bitmap_index bitmap ) { grs_bitmap * bmp; int i,org_i; org_i = 0; i = bitmap.index; Assert( i >= 0 ); Assert( i < MAX_BITMAP_FILES ); Assert( i < Num_bitmap_files ); Assert( Piggy_bitmap_cache_size > 0 ); if ( i < 1 ) return; if ( i >= MAX_BITMAP_FILES ) return; if ( i >= Num_bitmap_files ) return; if ( GameBitmapOffset[i] == 0 ) return; // A read-from-disk bitmap!!! if ( GameArg.SysLowMem ) { org_i = i; i = GameBitmapXlat[i]; // Xlat for low-memory settings! } bmp = &GameBitmaps[i]; if ( bmp->bm_flags & BM_FLAG_PAGED_OUT ) { stop_time(); ReDoIt: descent_critical_error = 0; PHYSFSX_fseek( Piggy_fp, GameBitmapOffset[i], SEEK_SET ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } gr_set_bitmap_flags (bmp, GameBitmapFlags[i]); gr_set_bitmap_data (bmp, &Piggy_bitmap_cache_data [Piggy_bitmap_cache_next]); if ( bmp->bm_flags & BM_FLAG_RLE ) { int zsize = 0; descent_critical_error = 0; zsize = PHYSFSX_readInt(Piggy_fp); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } // GET JOHN NOW IF YOU GET THIS ASSERT!!! Assert( Piggy_bitmap_cache_next+zsize < Piggy_bitmap_cache_size ); if ( Piggy_bitmap_cache_next+zsize >= Piggy_bitmap_cache_size ) { piggy_bitmap_page_out_all(); goto ReDoIt; } memcpy( &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], &zsize, sizeof(int) ); Piggy_bitmap_cache_next += sizeof(int); descent_critical_error = 0; PHYSFS_read( Piggy_fp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, zsize-4 ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } if (MacPig) { rle_swap_0_255(bmp); memcpy(&zsize, bmp->bm_data, 4); } Piggy_bitmap_cache_next += zsize-4; } else { // GET JOHN NOW IF YOU GET THIS ASSERT!!! Assert( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) < Piggy_bitmap_cache_size ); if ( Piggy_bitmap_cache_next+(bmp->bm_h*bmp->bm_w) >= Piggy_bitmap_cache_size ) { piggy_bitmap_page_out_all(); goto ReDoIt; } descent_critical_error = 0; PHYSFS_read( Piggy_fp, &Piggy_bitmap_cache_data[Piggy_bitmap_cache_next], 1, bmp->bm_h*bmp->bm_w ); if ( descent_critical_error ) { piggy_critical_error(); goto ReDoIt; } if (MacPig) swap_0_255(bmp); Piggy_bitmap_cache_next+=bmp->bm_h*bmp->bm_w; } compute_average_rgb(bmp, bmp->avg_color_rgb); start_time(); } if ( GameArg.SysLowMem ) { if ( org_i != i ) GameBitmaps[org_i] = GameBitmaps[i]; } } void piggy_bitmap_page_out_all() { int i; Piggy_bitmap_cache_next = 0; piggy_page_flushed++; texmerge_flush(); rle_cache_flush(); for (i=0; i 0 ) { // Don't page out bitmaps read from disk!!! GameBitmaps[i].bm_flags = BM_FLAG_PAGED_OUT; gr_set_bitmap_data (&GameBitmaps[i], Piggy_bitmap_cache_data); } } } void piggy_load_level_data() { piggy_bitmap_page_out_all(); paging_touch_all(); } #ifdef EDITOR void piggy_dump_all() { int i, xlat_offset; PHYSFS_file * fp; #ifndef RELEASE PHYSFS_file * fp1; PHYSFS_file * fp2; #endif char * filename; int data_offset; int org_offset; DiskBitmapHeader bmh; DiskSoundHeader sndh; int header_offset; char subst_name[32]; #ifdef NO_DUMP_SOUNDS Num_sound_files = 0; Num_sound_files_new = 0; #endif // { // bitmap_index bi; // bi.index = 614; // PIGGY_PAGE_IN( bi ); // count_colors( bi.index, &GameBitmaps[bi.index] ); // key_getch(); // } // { // bitmap_index bi; // bi.index = 478; // PIGGY_PAGE_IN( bi ); // Int3(); // count_colors( bi.index, &GameBitmaps[bi.index] ); // key_getch(); // } // { // bitmap_index bi; // bi.index = 1398; // PIGGY_PAGE_IN( bi ); // count_colors( bi.index, &GameBitmaps[bi.index] ); // key_getch(); // } // { // bitmap_index bi; // bi.index = 642; // PIGGY_PAGE_IN( bi ); // count_colors( bi.index, &GameBitmaps[bi.index] ); // key_getch(); // } // { // bitmap_index bi; // bi.index = 529; // PIGGY_PAGE_IN( bi ); // count_colors( bi.index, &GameBitmaps[bi.index] ); // key_getch(); // } // exit(0); // if ((Num_bitmap_files_new == 0) && (Num_sound_files_new == 0) ) return; for (i=0; i < Num_bitmap_files; i++ ) { bitmap_index bi; bi.index = i; PIGGY_PAGE_IN( bi ); } piggy_close_file(); filename = SHAREPATH "descent.pig"; fp = PHYSFSX_openWriteBuffered( filename ); Assert( fp!=NULL ); #ifndef RELEASE fp1 = PHYSFSX_openWriteBuffered( "piggy.lst" ); fp2 = PHYSFSX_openWriteBuffered( "piggy.all" ); #endif i = 0; PHYSFS_write( fp, &i, sizeof(int), 1 ); bm_write_all(fp); xlat_offset = PHYSFS_tell(fp); PHYSFS_write( fp, GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1 ); i = PHYSFS_tell(fp); PHYSFSX_fseek( fp, 0, SEEK_SET ); PHYSFS_write( fp, &i, sizeof(int), 1 ); PHYSFSX_fseek( fp, i, SEEK_SET ); Num_bitmap_files--; PHYSFS_write( fp, &Num_bitmap_files, sizeof(int), 1 ); Num_bitmap_files++; PHYSFS_write( fp, &Num_sound_files, sizeof(int), 1 ); header_offset = PHYSFS_tell(fp); header_offset += ((Num_bitmap_files-1)*sizeof(DiskBitmapHeader)) + (Num_sound_files*sizeof(DiskSoundHeader)); data_offset = header_offset; for (i=1; i < Num_bitmap_files; i++ ) { int *size; grs_bitmap *bmp; { char * p, *p1; p = strchr(AllBitmaps[i].name,'#'); if (p) { int n; p1 = p; p1++; n = atoi(p1); *p = 0; #ifndef RELEASE if (n==0) { PHYSFSX_printf( fp2, "%s.abm\n", AllBitmaps[i].name ); } #endif memcpy( bmh.name, AllBitmaps[i].name, 8 ); Assert( n <= 63 ); bmh.dflags = DBM_FLAG_ABM + n; *p = '#'; }else { #ifndef RELEASE PHYSFSX_printf( fp2, "%s.bbm\n", AllBitmaps[i].name ); #endif memcpy( bmh.name, AllBitmaps[i].name, 8 ); bmh.dflags = 0; } } bmp = &GameBitmaps[i]; Assert( !(bmp->bm_flags&BM_FLAG_PAGED_OUT) ); #ifndef RELEASE PHYSFSX_printf( fp1, "BMP: %s, size %d bytes", AllBitmaps[i].name, bmp->bm_rowsize * bmp->bm_h ); #endif org_offset = PHYSFS_tell(fp); bmh.offset = data_offset - header_offset; PHYSFSX_fseek( fp, data_offset, SEEK_SET ); if ( bmp->bm_flags & BM_FLAG_RLE ) { size = (int *)bmp->bm_data; PHYSFS_write( fp, bmp->bm_data, sizeof(ubyte), *size ); data_offset += *size; //bmh.data_length = *size; #ifndef RELEASE PHYSFSX_printf( fp1, ", and is already compressed to %d bytes.\n", *size ); #endif } else { PHYSFS_write( fp, bmp->bm_data, sizeof(ubyte), bmp->bm_rowsize * bmp->bm_h ); data_offset += bmp->bm_rowsize * bmp->bm_h; //bmh.data_length = bmp->bm_rowsize * bmp->bm_h; #ifndef RELEASE PHYSFSX_printf( fp1, ".\n" ); #endif } PHYSFSX_fseek( fp, org_offset, SEEK_SET ); if ( GameBitmaps[i].bm_w > 255 ) { Assert( GameBitmaps[i].bm_w < 512 ); bmh.width = GameBitmaps[i].bm_w - 256; bmh.dflags |= DBM_FLAG_LARGE; } else { bmh.width = GameBitmaps[i].bm_w; } Assert( GameBitmaps[i].bm_h < 256 ); bmh.height = GameBitmaps[i].bm_h; bmh.flags = GameBitmaps[i].bm_flags; if (piggy_is_substitutable_bitmap( AllBitmaps[i].name, subst_name )) { bitmap_index other_bitmap; other_bitmap = piggy_find_bitmap( subst_name ); GameBitmapXlat[i] = other_bitmap.index; bmh.flags |= BM_FLAG_PAGED_OUT; } else { #ifdef BUILD_PSX_DATA count_colors( i, &GameBitmaps[i] ); #endif bmh.flags &= ~BM_FLAG_PAGED_OUT; } bmh.avg_color=GameBitmaps[i].avg_color; PHYSFS_write( fp, &bmh, sizeof(DiskBitmapHeader), 1 ); // Mark as a bitmap } for (i=0; i < Num_sound_files; i++ ) { digi_sound *snd; snd = &GameSounds[i]; strcpy( sndh.name, AllSounds[i].name ); #ifdef ALLEGRO sndh.length = GameSounds[i].len; #else sndh.length = GameSounds[i].length; #endif sndh.offset = data_offset - header_offset; org_offset = PHYSFS_tell(fp); PHYSFSX_fseek( fp, data_offset, SEEK_SET ); sndh.data_length = sndh.length; PHYSFS_write( fp, snd->data, sizeof(ubyte), sndh.length ); data_offset += sndh.length; PHYSFSX_fseek( fp, org_offset, SEEK_SET ); PHYSFS_write( fp, &sndh, sizeof(DiskSoundHeader), 1 ); // Mark as a bitmap #ifndef RELEASE PHYSFSX_printf( fp1, "SND: %s, size %d bytes\n", AllSounds[i].name, sndh.length ); PHYSFSX_printf( fp2, "%s.raw\n", AllSounds[i].name ); #endif } PHYSFSX_fseek( fp, xlat_offset, SEEK_SET ); PHYSFS_write( fp, GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1 ); PHYSFS_close(fp); #ifndef RELEASE PHYSFSX_printf( fp1, " Dumped %d assorted bitmaps.\n", Num_bitmap_files ); PHYSFSX_printf( fp1, " Dumped %d assorted sounds.\n", Num_sound_files ); PHYSFS_close(fp1); PHYSFS_close(fp2); #endif #ifdef BUILD_PSX_DATA fp = PHYSFSX_openWriteBuffered( "psx/descent.dat" ); PHYSFS_write( fp, &i, sizeof(int), 1 ); bm_write_all(fp); PHYSFS_write( fp, GameBitmapXlat, sizeof(ushort)*MAX_BITMAP_FILES, 1 ); PHYSFS_close(fp); #endif // Never allow the game to run after building pig. exit(0); } #endif void piggy_close() { int i; custom_close(); piggy_close_file(); //added ifndef on 10/04/98 by Matt Mueller to fix crash on exit bug -- killed 2000/02/06 since they don't seem to cause crash anymore. heh. //#ifndef __LINUX__ if (BitmapBits) d_free(BitmapBits); if ( SoundBits ) d_free( SoundBits ); for (i = 0; i < Num_sound_files; i++) if (SoundOffset[i] == 0) d_free(GameSounds[i].data); //#endif //end addition -MM hashtable_free( &AllBitmapsNames ); hashtable_free( &AllDigiSndNames ); } int piggy_does_bitmap_exist_slow( char * name ) { int i; for (i=0; iindex = PHYSFSX_readShort(fp); } /* * reads n bitmap_index structs from a PHYSFS_file */ int bitmap_index_read_n(bitmap_index *bi, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) bi[i].index = PHYSFSX_readShort(fp); return i; } dxx-rebirth-0.58.1-d1x/main/piggy.h000066400000000000000000000067711217717257200170010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Interface to piggy functions. * */ #ifndef _PIGGY_H #define _PIGGY_H #include "physfsx.h" #include "digi.h" #include "sounds.h" #define D1_SHARE_BIG_PIGSIZE 5092871 // v1.0 - 1.4 before RLE compression #define D1_SHARE_10_PIGSIZE 2529454 // v1.0 - 1.2 #define D1_SHARE_PIGSIZE 2509799 // v1.4 #define D1_10_BIG_PIGSIZE 7640220 // v1.0 before RLE compression #define D1_10_PIGSIZE 4520145 // v1.0 #define D1_PIGSIZE 4920305 // v1.4 - 1.5 (Incl. OEM v1.4a) #define D1_OEM_PIGSIZE 5039735 // v1.0 #define D1_MAC_PIGSIZE 3975533 #define D1_MAC_SHARE_PIGSIZE 2714487 typedef struct bitmap_index { ushort index; } bitmap_index; extern int MacPig; extern int PCSharePig; extern ubyte bogus_data[64 * 64]; extern grs_bitmap bogus_bitmap; extern ubyte bogus_bitmap_initialized; extern digi_sound bogus_sound; int properties_init(); void piggy_close(); void piggy_dump_all(); bitmap_index piggy_register_bitmap( grs_bitmap * bmp, char * name, int in_file ); int piggy_register_sound( digi_sound * snd, char * name, int in_file ); bitmap_index piggy_find_bitmap( char * name ); int piggy_find_sound( char * name ); void piggy_read_bitmap_data(grs_bitmap * bmp); void piggy_read_sound_data(digi_sound *snd); void piggy_load_level_data(); #ifdef SHAREWARE #define MAX_BITMAP_FILES 1500 #define MAX_SOUND_FILES MAX_SOUNDS #else /* */ #define MAX_BITMAP_FILES 1800 #define MAX_SOUND_FILES MAX_SOUNDS #endif /* */ #define PIGGY_PC_SHAREWARE 2 //moved to sounds.h - extern digi_sound GameSounds[MAX_SOUND_FILES]; extern grs_bitmap GameBitmaps[MAX_BITMAP_FILES]; extern void piggy_bitmap_page_in( bitmap_index bmp ); extern void piggy_bitmap_page_out_all(); extern int piggy_page_flushed; // DPH (17/9/98): Mod to use static inline function rather than #define under // linux, as the #define has problems with linefeeds. #ifdef __LINUX__ # define PIGGY_PAGE_IN(bmp) _piggy_page_in(bmp) static inline void _piggy_page_in(bitmap_index bmp) { do { if ( GameBitmaps[(bmp).index].bm_flags & BM_FLAG_PAGED_OUT ) { piggy_bitmap_page_in( bmp ); } } while(0); } #else // __GNUC__ #define PIGGY_PAGE_IN(bmp) \ do { \ if ( GameBitmaps[(bmp).index].bm_flags & BM_FLAG_PAGED_OUT ) {\ piggy_bitmap_page_in( bmp ); \ } \ } while(0) #endif // __GNUC__ // DPH (17/9/98): End mod. void piggy_read_sounds(int pc_shareware); /* * reads a bitmap_index structure from a PHYSFS_file */ void bitmap_index_read(bitmap_index *bi, PHYSFS_file *fp); /* * reads n bitmap_index structs from a PHYSFS_file */ int bitmap_index_read_n(bitmap_index *bi, int n, PHYSFS_file *fp); #define REMOVE_EOL(s) remove_char((s),'\n') #define REMOVE_COMMENTS(s) remove_char((s),';') #define REMOVE_DOTS(s) remove_char((s),'.') #endif // _PIGGY_H dxx-rebirth-0.58.1-d1x/main/player.c000066400000000000000000000035221217717257200171400ustar00rootroot00000000000000 /* * * Player Stuff * */ #include "player.h" #include "byteswap.h" void player_rw_swap(player_rw *p, int swap) { int i; if (!swap) return; p->objnum = SWAPINT(p->objnum); p->n_packets_got = SWAPINT(p->n_packets_got); p->n_packets_sent = SWAPINT(p->n_packets_sent); p->flags = SWAPINT(p->flags); p->energy = SWAPINT(p->energy); p->shields = SWAPINT(p->shields); p->killer_objnum = SWAPSHORT(p->killer_objnum); for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) p->primary_ammo[i] = SWAPSHORT(p->primary_ammo[i]); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) p->secondary_ammo[i] = SWAPSHORT(p->secondary_ammo[i]); p->last_score = SWAPINT(p->last_score); p->score = SWAPINT(p->score); p->time_level = SWAPINT(p->time_level); p->time_total = SWAPINT(p->time_total); p->cloak_time = SWAPINT(p->cloak_time); p->invulnerable_time = SWAPINT(p->invulnerable_time); p->net_killed_total = SWAPSHORT(p->net_killed_total); p->net_kills_total = SWAPSHORT(p->net_kills_total); p->num_kills_level = SWAPSHORT(p->num_kills_level); p->num_kills_total = SWAPSHORT(p->num_kills_total); p->num_robots_level = SWAPSHORT(p->num_robots_level); p->num_robots_total = SWAPSHORT(p->num_robots_total); p->hostages_rescued_total = SWAPSHORT(p->hostages_rescued_total); p->hostages_total = SWAPSHORT(p->hostages_total); p->homing_object_dist = SWAPINT(p->homing_object_dist); } void player_ship_read(player_ship *ps, PHYSFS_file *fp) { int i; ps->model_num = PHYSFSX_readInt(fp); ps->expl_vclip_num = PHYSFSX_readInt(fp); ps->mass = PHYSFSX_readFix(fp); ps->drag = PHYSFSX_readFix(fp); ps->max_thrust = PHYSFSX_readFix(fp); ps->reverse_thrust = PHYSFSX_readFix(fp); ps->brakes = PHYSFSX_readFix(fp); ps->wiggle = PHYSFSX_readFix(fp); ps->max_rotthrust = PHYSFSX_readFix(fp); for (i = 0; i < N_PLAYER_GUNS; i++) PHYSFSX_readVector(&ps->gun_points[i], fp); } dxx-rebirth-0.58.1-d1x/main/player.h000066400000000000000000000207701217717257200171510ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Structure information for the player * */ #ifndef _PLAYER_H #define _PLAYER_H #include "inferno.h" #include "fix.h" #include "vecmat.h" #include "weapon.h" #define MAX_PLAYERS 8 #define MAX_MULTI_PLAYERS MAX_PLAYERS+3 // Initial player stat values #define INITIAL_ENERGY i2f(100) // 100% energy to start #define INITIAL_SHIELDS i2f(100) // 100% shields to start #define MAX_ENERGY i2f(200) // go up to 200 #define MAX_SHIELDS i2f(200) #define INITIAL_LIVES 3 // start off with 3 lives // Values for special flags #define PLAYER_FLAGS_INVULNERABLE 1 // Player is invincible #define PLAYER_FLAGS_BLUE_KEY 2 // Player has blue key #define PLAYER_FLAGS_RED_KEY 4 // Player has red key #define PLAYER_FLAGS_GOLD_KEY 8 // Player has gold key #define PLAYER_FLAGS_MAP_ALL 64 // Player can see unvisited areas on map #define PLAYER_FLAGS_QUAD_LASERS 1024 // Player shoots 4 at once #define PLAYER_FLAGS_CLOAKED 2048 // Player is cloaked for awhile #define CALLSIGN_LEN 8 // so can use as filename (was: 12) // Amount of time player is cloaked. #define CLOAK_TIME_MAX (F1_0*30) #define INVULNERABLE_TIME_MAX (F1_0*30) #define PLAYER_STRUCT_VERSION 16 //increment this every time player struct changes //When this structure changes, increment the constant SAVE_FILE_VERSION //in playsave.c typedef struct player { // Who am I data char callsign[CALLSIGN_LEN+1]; // The callsign of this player, for net purposes. ubyte net_address[6]; // The network address of the player. sbyte connected; // Is the player connected or not? int objnum; // What object number this player is. (made an int by mk because it's very often referenced) int n_packets_got; // How many packets we got from them int n_packets_sent; // How many packets we sent to them // -- make sure you're 4 byte aligned now! // Game data uint flags; // Powerup flags, see below... fix energy; // Amount of energy remaining. fix shields; // shields remaining (protection) ubyte lives; // Lives remaining, 0 = game over. sbyte level; // Current level player is playing. (must be signed for secret levels) ubyte laser_level; // Current level of the laser. sbyte starting_level; // What level the player started on. short killer_objnum; // Who killed me.... (-1 if no one) ubyte primary_weapon_flags; // bit set indicates the player has this weapon. ubyte secondary_weapon_flags; // bit set indicates the player has this weapon. ushort primary_ammo[MAX_PRIMARY_WEAPONS]; // How much ammo of each type. ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type. // -- make sure you're 4 byte aligned now // Statistics... int last_score; // Score at beginning of current level. int score; // Current score. fix time_level; // Level time played fix time_total; // Game time played (high word = seconds) fix64 cloak_time; // Time cloaked fix64 invulnerable_time; // Time invulnerable short KillGoalCount; // Num of players killed this level short net_killed_total; // Number of times killed total short net_kills_total; // Number of net kills total short num_kills_level; // Number of kills this level short num_kills_total; // Number of kills total short num_robots_level; // Number of initial robots this level short num_robots_total; // Number of robots total ushort hostages_rescued_total; // Total number of hostages rescued. ushort hostages_total; // Total number of hostages. ubyte hostages_on_board; // Number of hostages on ship. ubyte hostages_level; // Number of hostages on this level. fix homing_object_dist; // Distance of nearest homing object. sbyte hours_level; // Hours played (since time_total can only go up to 9 hours) sbyte hours_total; // Hours played (since time_total can only go up to 9 hours) } __pack__ player; // Same as above but structure how Savegames expect typedef struct player_rw { // Who am I data char callsign[CALLSIGN_LEN+1]; // The callsign of this player, for net purposes. ubyte net_address[6]; // The network address of the player. sbyte connected; // Is the player connected or not? int objnum; // What object number this player is. (made an int by mk because it's very often referenced) int n_packets_got; // How many packets we got from them int n_packets_sent; // How many packets we sent to them // -- make sure you're 4 byte aligned now! // Game data uint flags; // Powerup flags, see below... fix energy; // Amount of energy remaining. fix shields; // shields remaining (protection) ubyte lives; // Lives remaining, 0 = game over. sbyte level; // Current level player is playing. (must be signed for secret levels) ubyte laser_level; // Current level of the laser. sbyte starting_level; // What level the player started on. short killer_objnum; // Who killed me.... (-1 if no one) ubyte primary_weapon_flags; // bit set indicates the player has this weapon. ubyte secondary_weapon_flags; // bit set indicates the player has this weapon. ushort primary_ammo[MAX_PRIMARY_WEAPONS]; // How much ammo of each type. ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type. // -- make sure you're 4 byte aligned now // Statistics... int last_score; // Score at beginning of current level. int score; // Current score. fix time_level; // Level time played fix time_total; // Game time played (high word = seconds) fix cloak_time; // Time cloaked fix invulnerable_time; // Time invulnerable short net_killed_total; // Number of times killed total short net_kills_total; // Number of net kills total short num_kills_level; // Number of kills this level short num_kills_total; // Number of kills total short num_robots_level; // Number of initial robots this level short num_robots_total; // Number of robots total ushort hostages_rescued_total; // Total number of hostages rescued. ushort hostages_total; // Total number of hostages. ubyte hostages_on_board; // Number of hostages on ship. ubyte hostages_level; // Number of hostages on this level. fix homing_object_dist; // Distance of nearest homing object. sbyte hours_level; // Hours played (since time_total can only go up to 9 hours) sbyte hours_total; // Hours played (since time_total can only go up to 9 hours) } __pack__ player_rw; #define N_PLAYER_GUNS 8 #define N_PLAYER_SHIP_TEXTURES 32 typedef struct player_ship { int model_num; int expl_vclip_num; fix mass,drag; fix max_thrust,reverse_thrust,brakes; //low_thrust fix wiggle; fix max_rotthrust; vms_vector gun_points[N_PLAYER_GUNS]; } __pack__ player_ship; extern int N_players; // Number of players ( >1 means a net game, eh?) extern int Player_num; // The player number who is on the console. extern player Players[MAX_PLAYERS]; // Misc player info extern player_ship *Player_ship; /* * reads a player_ship structure from a PHYSFS_file */ void player_ship_read(player_ship *ps, PHYSFS_file *fp); void player_rw_swap(player_rw *p, int swap); #endif dxx-rebirth-0.58.1-d1x/main/playsave.c000066400000000000000000001077321217717257200175000ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to load & save player games * */ #include #include #include #include #include #include "dxxerror.h" #include "gameseq.h" #include "player.h" #include "playsave.h" #include "joy.h" #include "digi.h" #include "newmenu.h" #include "palette.h" #include "menu.h" #include "config.h" #include "text.h" #include "state.h" #include "u_mem.h" #include "strutil.h" #include "strio.h" #include "vers_id.h" #include "byteswap.h" #include "physfsx.h" #include "newdemo.h" #include "gauges.h" #include "args.h" //version 5 -> 6: added new highest level information //version 6 -> 7: stripped out the old saved_game array. //version 7 -> 8: readded the old saved_game array since this is needed // for shareware saved games //the shareware is level 4 #define SAVE_FILE_ID 0x44504c52 /* 'DPLR' */ #define SAVED_GAME_VERSION 8 //increment this every time saved_game struct changes #define COMPATIBLE_SAVED_GAME_VERSION 4 #define COMPATIBLE_PLAYER_STRUCT_VERSION 16 struct player_config PlayerCfg; saved_game_sw saved_games[N_SAVE_SLOTS]; extern void InitWeaponOrdering(); int new_player_config() { int i=0; for (i=0;i='a'){ neg=1;/*I=p[0]-'a';*/ }else{ neg=0;/*I=p[0]-'A';*/ } i=0;*v=0; p++; while (p[i*2] && p[i*2+1] && p[i*2]!=' '){ c=(p[i*2]-33)+((p[i*2+1]-33)<<4); c^=effcode[i+neg]; *v+=c << (i*8); i++; } if (neg) *v *= -1; if (!p[i*2]) return NULL; return p+(i*2); } void plyr_read_stats_v(int *k, int *d){ char filename[PATH_MAX]; int k1=-1,k2=0,d1=-1,d2=0; PHYSFS_file *f; *k=0;*d=0;//in case the file doesn't exist. memset(filename, '\0', PATH_MAX); snprintf(filename,PATH_MAX,GameArg.SysUsePlayersDir?"Players/%s.eff":"%s.eff",Players[Player_num].callsign); f = PHYSFSX_openReadBuffered(filename); if(f) { char line[256],*word; if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"kills")) *k=atoi(line); d_free(word); } if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"deaths")) *d=atoi(line); d_free(word); } if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"key") && strlen(line)>10){ unsigned char *p; if (line[0]=='0' && line[1]=='1'){ if ((p=decode_stat((unsigned char*)line+3,&k1,effcode1))&& (p=decode_stat(p+1,&k2,effcode2))&& (p=decode_stat(p+1,&d1,effcode3))){ decode_stat(p+1,&d2,effcode4); } } } d_free(word); } if (k1!=k2 || k1!=*k || d1!=d2 || d1!=*d) { *k=0;*d=0; } } if(f) PHYSFS_close(f); } void plyr_read_stats() { plyr_read_stats_v(&PlayerCfg.NetlifeKills,&PlayerCfg.NetlifeKilled); } void plyr_save_stats() { int kills = PlayerCfg.NetlifeKills,deaths = PlayerCfg.NetlifeKilled, neg, i; char filename[PATH_MAX]; unsigned char buf[16],buf2[16],a; PHYSFS_file *f; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir?"Players/%s.eff":"%s.eff", Players[Player_num].callsign); f = PHYSFSX_openWriteBuffered(filename); if(!f) return; //broken! PHYSFSX_printf(f,"kills:%i\n",kills); PHYSFSX_printf(f,"deaths:%i\n",deaths); PHYSFSX_printf(f,"key:01 "); if (kills<0) { neg=1; kills*=-1; } else neg=0; for (i=0;kills;i++) { a=(kills & 0xFF) ^ effcode1[i+neg]; buf[i*2]=(a&0xF)+33; buf[i*2+1]=(a>>4)+33; a=(kills & 0xFF) ^ effcode2[i+neg]; buf2[i*2]=(a&0xF)+33; buf2[i*2+1]=(a>>4)+33; kills>>=8; } buf[i*2]=0; buf2[i*2]=0; if (neg) i+='a'; else i+='A'; PHYSFSX_printf(f,"%c%s %c%s ",i,buf,i,buf2); if (deaths<0) { neg=1; deaths*=-1; }else neg=0; for (i=0;deaths;i++) { a=(deaths & 0xFF) ^ effcode3[i+neg]; buf[i*2]=(a&0xF)+33; buf[i*2+1]=(a>>4)+33; a=(deaths & 0xFF) ^ effcode4[i+neg]; buf2[i*2]=(a&0xF)+33; buf2[i*2+1]=(a>>4)+33; deaths>>=8; } buf[i*2]=0; buf2[i*2]=0; if (neg) i+='a'; else i+='A'; PHYSFSX_printf(f,"%c%s %c%s\n",i,buf,i,buf2); PHYSFS_close(f); } int write_player_d1x(char *filename) { PHYSFS_file *fout; int rc=0; char tempfile[PATH_MAX]; strcpy(tempfile,filename); tempfile[strlen(tempfile)-4]=0; strcat(tempfile,".pl$"); fout=PHYSFSX_openWriteBuffered(tempfile); if (!fout && GameArg.SysUsePlayersDir) { PHYSFS_mkdir("Players/"); //try making directory fout=PHYSFSX_openWriteBuffered(tempfile); } if(fout) { PHYSFSX_printf(fout,"[D1X Options]\n"); PHYSFSX_printf(fout,"[weapon reorder]\n"); PHYSFSX_printf(fout,"primary=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",PlayerCfg.PrimaryOrder[0], PlayerCfg.PrimaryOrder[1], PlayerCfg.PrimaryOrder[2],PlayerCfg.PrimaryOrder[3], PlayerCfg.PrimaryOrder[4], PlayerCfg.PrimaryOrder[5]); PHYSFSX_printf(fout,"secondary=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",PlayerCfg.SecondaryOrder[0], PlayerCfg.SecondaryOrder[1], PlayerCfg.SecondaryOrder[2],PlayerCfg.SecondaryOrder[3], PlayerCfg.SecondaryOrder[4], PlayerCfg.SecondaryOrder[5]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[keyboard]\n"); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.KeyboardSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.KeyboardSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.KeyboardSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.KeyboardSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.KeyboardSens[4]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[joystick]\n"); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.JoystickSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.JoystickSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.JoystickSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.JoystickSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.JoystickSens[4]); PHYSFSX_printf(fout,"sensitivity5=%d\n",PlayerCfg.JoystickSens[5]); PHYSFSX_printf(fout,"deadzone0=%d\n",PlayerCfg.JoystickDead[0]); PHYSFSX_printf(fout,"deadzone1=%d\n",PlayerCfg.JoystickDead[1]); PHYSFSX_printf(fout,"deadzone2=%d\n",PlayerCfg.JoystickDead[2]); PHYSFSX_printf(fout,"deadzone3=%d\n",PlayerCfg.JoystickDead[3]); PHYSFSX_printf(fout,"deadzone4=%d\n",PlayerCfg.JoystickDead[4]); PHYSFSX_printf(fout,"deadzone5=%d\n",PlayerCfg.JoystickDead[5]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[mouse]\n"); PHYSFSX_printf(fout,"flightsim=%d\n",PlayerCfg.MouseFlightSim); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.MouseSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.MouseSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.MouseSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.MouseSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.MouseSens[4]); PHYSFSX_printf(fout,"sensitivity5=%d\n",PlayerCfg.MouseSens[5]); PHYSFSX_printf(fout,"fsdead=%d\n",PlayerCfg.MouseFSDead); PHYSFSX_printf(fout,"fsindi=%d\n",PlayerCfg.MouseFSIndicator); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[weapon keys v2]\n"); PHYSFSX_printf(fout,"1=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[0],PlayerCfg.KeySettingsD1X[1],PlayerCfg.KeySettingsD1X[2]); PHYSFSX_printf(fout,"2=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[3],PlayerCfg.KeySettingsD1X[4],PlayerCfg.KeySettingsD1X[5]); PHYSFSX_printf(fout,"3=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[6],PlayerCfg.KeySettingsD1X[7],PlayerCfg.KeySettingsD1X[8]); PHYSFSX_printf(fout,"4=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[9],PlayerCfg.KeySettingsD1X[10],PlayerCfg.KeySettingsD1X[11]); PHYSFSX_printf(fout,"5=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[12],PlayerCfg.KeySettingsD1X[13],PlayerCfg.KeySettingsD1X[14]); PHYSFSX_printf(fout,"6=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[15],PlayerCfg.KeySettingsD1X[16],PlayerCfg.KeySettingsD1X[17]); PHYSFSX_printf(fout,"7=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[18],PlayerCfg.KeySettingsD1X[19],PlayerCfg.KeySettingsD1X[20]); PHYSFSX_printf(fout,"8=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[21],PlayerCfg.KeySettingsD1X[22],PlayerCfg.KeySettingsD1X[23]); PHYSFSX_printf(fout,"9=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[24],PlayerCfg.KeySettingsD1X[25],PlayerCfg.KeySettingsD1X[26]); PHYSFSX_printf(fout,"0=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsD1X[27],PlayerCfg.KeySettingsD1X[28],PlayerCfg.KeySettingsD1X[29]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[cockpit]\n"); PHYSFSX_printf(fout,"mode=%i\n",PlayerCfg.CockpitMode[0]); PHYSFSX_printf(fout,"hud=%i\n",PlayerCfg.HudMode); PHYSFSX_printf(fout,"rettype=%i\n",PlayerCfg.ReticleType); PHYSFSX_printf(fout,"retrgba=%i,%i,%i,%i\n",PlayerCfg.ReticleRGBA[0],PlayerCfg.ReticleRGBA[1],PlayerCfg.ReticleRGBA[2],PlayerCfg.ReticleRGBA[3]); PHYSFSX_printf(fout,"retsize=%i\n",PlayerCfg.ReticleSize); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[toggles]\n"); PHYSFSX_printf(fout,"persistentdebris=%i\n",PlayerCfg.PersistentDebris); PHYSFSX_printf(fout,"prshot=%i\n",PlayerCfg.PRShot); PHYSFSX_printf(fout,"noredundancy=%i\n",PlayerCfg.NoRedundancy); PHYSFSX_printf(fout,"multimessages=%i\n",PlayerCfg.MultiMessages); PHYSFSX_printf(fout,"norankings=%i\n",PlayerCfg.NoRankings); PHYSFSX_printf(fout,"bombgauge=%i\n",PlayerCfg.BombGauge); PHYSFSX_printf(fout,"automapfreeflight=%i\n",PlayerCfg.AutomapFreeFlight); PHYSFSX_printf(fout,"nofireautoselect=%i\n",PlayerCfg.NoFireAutoselect); PHYSFSX_printf(fout,"cycleautoselectonly=%i\n",PlayerCfg.CycleAutoselectOnly); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[graphics]\n"); PHYSFSX_printf(fout,"alphaeffects=%i\n",PlayerCfg.AlphaEffects); PHYSFSX_printf(fout,"dynlightcolor=%i\n",PlayerCfg.DynLightColor); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[plx version]\n"); PHYSFSX_printf(fout,"plx version=%s\n", VERSION); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[end]\n"); PHYSFS_close(fout); if(rc==0) { PHYSFS_delete(filename); rc = PHYSFSX_rename(tempfile,filename); } return rc; } else return errno; } //read in the player's saved games. returns errno (0 == no error) int read_player_file() { char filename[PATH_MAX]; PHYSFS_file *file; int player_file_size, shareware_file = -1, id = 0; short saved_game_version, player_struct_version; Assert(Player_num>=0 && Player_num PlayerCfg.HighestLevels[i].LevelNum) PlayerCfg.HighestLevels[i].LevelNum = levelnum; write_player_file(); } //gets the player's highest level from the file for this mission int get_highest_level(void) { int i; int highest_saturn_level = 0; read_player_file(); #ifndef SHAREWARE #ifndef SATURN if (strlen(Current_mission_filename)==0 ) { for (i=0;i i ) i = highest_saturn_level; return i; } //write out player's saved games. returns errno (0 == no error) int write_player_file() { char filename[PATH_MAX]; PHYSFS_file *file; int errno_ret, i; if ( Newdemo_state == ND_STATE_PLAYBACK ) return -1; errno_ret = WriteConfigFile(); memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.plx" : "%.8s.plx", Players[Player_num].callsign); write_player_d1x(filename); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.plr" : "%.8s.plr", Players[Player_num].callsign); file = PHYSFSX_openWriteBuffered(filename); if (!file) return errno; PHYSFS_writeULE32(file, SAVE_FILE_ID); PHYSFS_writeULE16(file, SAVED_GAME_VERSION); PHYSFS_writeULE16(file, PLAYER_STRUCT_VERSION); PHYSFS_writeSLE32(file, PlayerCfg.NHighestLevels); PHYSFS_writeSLE32(file, PlayerCfg.DefaultDifficulty); PHYSFS_writeSLE32(file, PlayerCfg.AutoLeveling); errno_ret = EZERO; //write higest level info if ((PHYSFS_write( file, PlayerCfg.HighestLevels, sizeof(hli), PlayerCfg.NHighestLevels) != PlayerCfg.NHighestLevels)) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } if (PHYSFS_write( file, saved_games,sizeof(saved_games),1) != 1) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } #ifdef NETWORK if ((PHYSFS_write( file, PlayerCfg.NetworkMessageMacro, MAX_MESSAGE_LEN, 4) != 4)) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } #else { //PHYSFS_seek( file, PHYSFS_tell(file)+MAX_MESSAGE_LEN * 4 ); // Seeking is bad for Mac OS 9 char dummy[MAX_MESSAGE_LEN][4]; if ((PHYSFS_write( file, dummy, MAX_MESSAGE_LEN, 4) != 4)) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } } #endif //write kconfig info { if (PHYSFS_write(file, PlayerCfg.KeySettings[0], sizeof(PlayerCfg.KeySettings[0]), 1) != 1) errno_ret=errno; if (PHYSFS_write(file, PlayerCfg.KeySettings[1], sizeof(PlayerCfg.KeySettings[1]), 1) != 1) errno_ret=errno; for (i = 0; i < MAX_CONTROLS*3; i++) if (PHYSFS_write(file, "0", sizeof(ubyte), 1) != 1) // Skip obsolete Flightstick/Thrustmaster/Gravis map fields errno_ret=errno; if (PHYSFS_write(file, PlayerCfg.KeySettings[2], sizeof(PlayerCfg.KeySettings[2]), 1) != 1) errno_ret=errno; for (i = 0; i < MAX_CONTROLS; i++) if (PHYSFS_write(file, "0", sizeof(ubyte), 1) != 1) // Skip obsolete Cyberman map field errno_ret=errno; if(errno_ret == EZERO) { ubyte old_avg_joy_sensitivity = 8; if (PHYSFS_write( file, &PlayerCfg.ControlType, sizeof(ubyte), 1 )!=1) errno_ret=errno; else if (PHYSFS_write( file, &old_avg_joy_sensitivity, sizeof(ubyte), 1 )!=1) errno_ret=errno; } } if (!PHYSFS_close(file)) errno_ret = errno; if (errno_ret != EZERO) { PHYSFS_delete(filename); //delete bogus file nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s",TXT_ERROR_WRITING_PLR, strerror(errno_ret)); } return errno_ret; } // read stored values from ngp file to netgame_info void read_netgame_profile(netgame_info *ng) { char filename[PATH_MAX], line[50], *token, *value, *ptr; PHYSFS_file *file; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", Players[Player_num].callsign); if (!PHYSFSX_exists(filename,0)) return; file = PHYSFSX_openReadBuffered(filename); if (!file) return; // NOTE that we do not set any defaults here or even initialize netgame_info. For flexibility, leave that to the function calling this. while (!PHYSFS_eof(file)) { memset(line, 0, 50); PHYSFSX_gets(file, line); ptr = &(line[0]); while (isspace(*ptr)) ptr++; if (*ptr != '\0') { token = strtok(ptr, "="); value = strtok(NULL, "="); if (!value) value = ""; if (!strcmp(token, "game_name")) { char * p; strncpy( ng->game_name, value, NETGAME_NAME_LEN+1 ); p = strchr( ng->game_name, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, "gamemode")) ng->gamemode = strtol(value, NULL, 10); else if (!strcmp(token, "RefusePlayers")) ng->RefusePlayers = strtol(value, NULL, 10); else if (!strcmp(token, "difficulty")) ng->difficulty = strtol(value, NULL, 10); else if (!strcmp(token, "game_flags")) ng->game_flags = strtol(value, NULL, 10); else if (!strcmp(token, "AllowedItems")) ng->AllowedItems = strtol(value, NULL, 10); else if (!strcmp(token, "ShowEnemyNames")) ng->ShowEnemyNames = strtol(value, NULL, 10); else if (!strcmp(token, "BrightPlayers")) ng->BrightPlayers = strtol(value, NULL, 10); else if (!strcmp(token, "InvulAppear")) ng->InvulAppear = strtol(value, NULL, 10); else if (!strcmp(token, "KillGoal")) ng->KillGoal = strtol(value, NULL, 10); else if (!strcmp(token, "PlayTimeAllowed")) ng->PlayTimeAllowed = strtol(value, NULL, 10); else if (!strcmp(token, "control_invul_time")) ng->control_invul_time = strtol(value, NULL, 10); else if (!strcmp(token, "PacketsPerSec")) ng->PacketsPerSec = strtol(value, NULL, 10); else if (!strcmp(token, "ShortPackets")) ng->ShortPackets = strtol(value, NULL, 10); else if (!strcmp(token, "NoFriendlyFire")) ng->NoFriendlyFire = strtol(value, NULL, 10); #ifdef USE_TRACKER else if (!strcmp(token, "Tracker")) ng->Tracker = strtol(value, NULL, 10); #endif } } PHYSFS_close(file); } // write values from netgame_info to ngp file void write_netgame_profile(netgame_info *ng) { char filename[PATH_MAX]; PHYSFS_file *file; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", Players[Player_num].callsign); file = PHYSFSX_openWriteBuffered(filename); if (!file) return; PHYSFSX_printf(file, "game_name=%s\n", ng->game_name); PHYSFSX_printf(file, "gamemode=%i\n", ng->gamemode); PHYSFSX_printf(file, "RefusePlayers=%i\n", ng->RefusePlayers); PHYSFSX_printf(file, "difficulty=%i\n", ng->difficulty); PHYSFSX_printf(file, "game_flags=%i\n", ng->game_flags); PHYSFSX_printf(file, "AllowedItems=%i\n", ng->AllowedItems); PHYSFSX_printf(file, "ShowEnemyNames=%i\n", ng->ShowEnemyNames); PHYSFSX_printf(file, "BrightPlayers=%i\n", ng->BrightPlayers); PHYSFSX_printf(file, "InvulAppear=%i\n", ng->InvulAppear); PHYSFSX_printf(file, "KillGoal=%i\n", ng->KillGoal); PHYSFSX_printf(file, "PlayTimeAllowed=%i\n", ng->PlayTimeAllowed); PHYSFSX_printf(file, "control_invul_time=%i\n", ng->control_invul_time); PHYSFSX_printf(file, "PacketsPerSec=%i\n", ng->PacketsPerSec); PHYSFSX_printf(file, "ShortPackets=%i\n", ng->ShortPackets); PHYSFSX_printf(file, "NoFriendlyFire=%i\n", ng->NoFriendlyFire); #ifdef USE_TRACKER PHYSFSX_printf(file, "Tracker=%i\n", ng->Tracker); #else PHYSFSX_printf(file, "Tracker=0\n"); #endif PHYSFSX_printf(file, "ngp version=%s\n",VERSION); PHYSFS_close(file); } dxx-rebirth-0.58.1-d1x/main/playsave.h000066400000000000000000000064441217717257200175030ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for playsave.c * */ #ifndef _PLAYSAVE_H #define _PLAYSAVE_H #include "pstypes.h" #include "kconfig.h" #include "mission.h" #include "weapon.h" #include "multi.h" #include "player.h" #define N_SAVE_SLOTS 10 #define GAME_NAME_LEN 25 // +1 for terminating zero = 26 // NOTE: Obsolete structure - only kept for compability of shareware plr file typedef struct saved_game_sw { char name[GAME_NAME_LEN+1]; //extra char for terminating zero struct player_rw sg_player; int difficulty_level; //which level game is played at int primary_weapon; //which weapon selected int secondary_weapon; //which weapon selected int cockpit_mode; //which cockpit mode selected int window_w,window_h; //size of player's window int next_level_num; //which level we're going to int auto_leveling_on; //does player have autoleveling on? } __pack__ saved_game_sw; typedef struct hli { char Shortname[9]; ubyte LevelNum; } hli; typedef struct player_config { ubyte ControlType; ubyte PrimaryOrder[MAX_PRIMARY_WEAPONS+1]; ubyte SecondaryOrder[MAX_SECONDARY_WEAPONS+1]; ubyte KeySettings[3][MAX_CONTROLS]; ubyte KeySettingsD1X[MAX_D1X_CONTROLS]; int DefaultDifficulty; int AutoLeveling; short NHighestLevels; hli HighestLevels[MAX_MISSIONS]; int KeyboardSens[5]; int JoystickSens[6]; int JoystickDead[6]; ubyte MouseFlightSim; int MouseSens[6]; int MouseFSDead; int MouseFSIndicator; int CockpitMode[2]; // 0 saves the "real" cockpit, 1 also saves letterbox and rear. Used to properly switch between modes and restore the real one. char NetworkMessageMacro[4][MAX_MESSAGE_LEN]; int NetlifeKills; int NetlifeKilled; ubyte ReticleType; int ReticleRGBA[4]; int ReticleSize; int HudMode; int PersistentDebris; int PRShot; ubyte NoRedundancy; ubyte MultiMessages; ubyte NoRankings; ubyte BombGauge; ubyte AutomapFreeFlight; ubyte NoFireAutoselect; ubyte CycleAutoselectOnly; int AlphaEffects; int DynLightColor; } __pack__ player_config; extern struct player_config PlayerCfg; extern int Default_leveling_on; // adb: EZERO looks like a watcom extension that's only used here #ifndef EZERO #define EZERO 0 #endif // Used to save kconfig values to disk. int write_player_file(); int new_player_config(); int read_player_file(); // set a new highest level for player for this mission void set_highest_level(int levelnum); // gets the player's highest level from the file for this mission int get_highest_level(void); void plyr_read_stats(); void plyr_save_stats(); void read_netgame_profile(netgame_info *ng); void write_netgame_profile(netgame_info *ng); #endif dxx-rebirth-0.58.1-d1x/main/polyobj.c000066400000000000000000000471021217717257200173240ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Hacked-in polygon objects * */ #include #include #include #ifdef DRIVE #include "drive.h" #else #include "inferno.h" #endif #include "polyobj.h" #include "vecmat.h" #include "3d.h" #include "dxxerror.h" #include "u_mem.h" #include "args.h" #ifndef DRIVE #include "texmap.h" #include "bm.h" #include "textures.h" #include "object.h" #include "lighting.h" #include "piggy.h" #endif #include "byteswap.h" #include "render.h" #ifdef OGL #include "ogl_init.h" #endif polymodel Polygon_models[MAX_POLYGON_MODELS]; // = {&bot11,&bot17,&robot_s2,&robot_b2,&bot11,&bot17,&robot_s2,&robot_b2}; int N_polygon_models = 0; #define MAX_POLYGON_VECS 1000 g3s_point robot_points[MAX_POLYGON_VECS]; #define PM_COMPATIBLE_VERSION 6 #define PM_OBJFILE_VERSION 8 int Pof_file_end; int Pof_addr; #define MODEL_BUF_SIZE 32768 void _pof_cfseek(int len,int type) { switch (type) { case SEEK_SET: Pof_addr = len; break; case SEEK_CUR: Pof_addr += len; break; case SEEK_END: Assert(len <= 0); // seeking from end, better be moving back. Pof_addr = Pof_file_end + len; break; } if (Pof_addr > MODEL_BUF_SIZE) Int3(); } #define pof_cfseek(_buf,_len,_type) _pof_cfseek((_len),(_type)) int pof_read_int(ubyte *bufp) { int i; i = *((int *) &bufp[Pof_addr]); Pof_addr += 4; return INTEL_INT(i); // if (PHYSFS_read(f,&i,sizeof(i),1) != 1) // Error("Unexpected end-of-file while reading object"); // // return i; } size_t pof_cfread(void *dst, size_t elsize, size_t nelem, ubyte *bufp) { if (Pof_addr + nelem*elsize > Pof_file_end) return 0; memcpy(dst, &bufp[Pof_addr], elsize*nelem); Pof_addr += elsize*nelem; if (Pof_addr > MODEL_BUF_SIZE) Int3(); return nelem; } // #define new_read_int(i,f) PHYSFS_read((f),&(i),sizeof(i),1) #define new_pof_read_int(i,f) pof_cfread(&(i),sizeof(i),1,(f)) short pof_read_short(ubyte *bufp) { short s; s = *((short *) &bufp[Pof_addr]); Pof_addr += 2; return INTEL_SHORT(s); // if (PHYSFS_read(f,&s,sizeof(s),1) != 1) // Error("Unexpected end-of-file while reading object"); // // return s; } void pof_read_string(char *buf,int max, ubyte *bufp) { int i; for (i=0; i= 1); for (i = 1; i < no_chunks; i++) if (old_dest(chunk_list[i]) < old_dest(chunk_list[first_index])) first_index = i; return first_index; } #define SHIFT_SPACE 500 // increase if insufficent void align_polygon_model_data(polymodel *pm) { int i, chunk_len; int total_correction = 0; ubyte *cur_old, *cur_new; chunk cur_ch; chunk ch_list[MAX_CHUNKS]; int no_chunks = 0; int tmp_size = pm->model_data_size + SHIFT_SPACE; ubyte *tmp = d_malloc(tmp_size); // where we build the aligned version of pm->model_data Assert(tmp != NULL); //start with first chunk (is always aligned!) cur_old = pm->model_data; cur_new = tmp; chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks); memcpy(cur_new, cur_old, chunk_len); while (no_chunks > 0) { int first_index = get_first_chunks_index(ch_list, no_chunks); cur_ch = ch_list[first_index]; // remove first chunk from array: no_chunks--; for (i = first_index; i < no_chunks; i++) ch_list[i] = ch_list[i + 1]; // if (new) address unaligned: if ((u_int32_t)new_dest(cur_ch) % 4L != 0) { // calculate how much to move to be aligned short to_shift = 4 - (u_int32_t)new_dest(cur_ch) % 4L; // correct chunks' addresses cur_ch.correction += to_shift; for (i = 0; i < no_chunks; i++) ch_list[i].correction += to_shift; total_correction += to_shift; Assert((u_int32_t)new_dest(cur_ch) % 4L == 0); Assert(total_correction <= SHIFT_SPACE); // if you get this, increase SHIFT_SPACE } //write (corrected) chunk for current chunk: *((short *)(cur_ch.new_base + cur_ch.offset)) = INTEL_SHORT(cur_ch.correction + INTEL_SHORT(*((short *)(cur_ch.old_base + cur_ch.offset)))); //write (correctly aligned) chunk: cur_old = old_dest(cur_ch); cur_new = new_dest(cur_ch); chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks); memcpy(cur_new, cur_old, chunk_len); //correct submodel_ptr's for pm, too for (i = 0; i < MAX_SUBMODELS; i++) if (pm->model_data + pm->submodel_ptrs[i] >= cur_old && pm->model_data + pm->submodel_ptrs[i] < cur_old + chunk_len) pm->submodel_ptrs[i] += (cur_new - tmp) - (cur_old - pm->model_data); } d_free(pm->model_data); pm->model_data_size += total_correction; pm->model_data = d_malloc(pm->model_data_size); Assert(pm->model_data != NULL); memcpy(pm->model_data, tmp, pm->model_data_size); d_free(tmp); } #endif //def WORDS_NEED_ALIGNMENT //reads a binary file containing a 3d model polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r) { PHYSFS_file *ifile; short version; int id,len, next_chunk; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL) Error("Can't open file <%s>",filename); Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile)); PHYSFS_close(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); next_chunk = Pof_addr + len; switch (id) { case ID_OHDR: { //Object header vms_vector pmmin,pmmax; pm->n_models = pof_read_int(model_buf); pm->rad = pof_read_int(model_buf); Assert(pm->n_models <= MAX_SUBMODELS); pof_read_vecs(&pmmin,1,model_buf); pof_read_vecs(&pmmax,1,model_buf); break; } case ID_SOBJ: { //Subobject header int n; n = pof_read_short(model_buf); Assert(n < MAX_SUBMODELS); pm->submodel_parents[n] = pof_read_short(model_buf); pof_read_vecs(&pm->submodel_norms[n],1,model_buf); pof_read_vecs(&pm->submodel_pnts[n],1,model_buf); pof_read_vecs(&pm->submodel_offsets[n],1,model_buf); pm->submodel_rads[n] = pof_read_int(model_buf); //radius pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset break; } #ifndef DRIVE case ID_GUNS: { //List of guns on this object if (r) { int i; vms_vector gun_dir; r->n_guns = pof_read_int(model_buf); Assert(r->n_guns <= MAX_GUNS); for (i=0;in_guns;i++) { int id; id = pof_read_short(model_buf); r->gun_submodels[id] = pof_read_short(model_buf); Assert(r->gun_submodels[id] != 0xff); pof_read_vecs(&r->gun_points[id],1,model_buf); if (version >= 7) pof_read_vecs(&gun_dir,1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); break; } case ID_ANIM: //Animation data if (r) { int n_frames,f,m; n_frames = pof_read_short(model_buf); Assert(n_frames == N_ANIM_STATES); for (m=0;mn_models;m++) for (f=0;fmodel_data = d_malloc(len); pm->model_data_size = len; pof_cfread(pm->model_data,1,len,model_buf); break; default: pof_cfseek(model_buf,len,SEEK_CUR); break; } if ( version >= 8 ) // Version 8 needs 4-byte alignment!!! pof_cfseek(model_buf,next_chunk,SEEK_SET); } #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #endif #ifdef WORDS_BIGENDIAN swap_polygon_model_data(pm->model_data); #endif return pm; } //reads the gun information for a model //fills in arrays gun_points & gun_dirs, returns the number of guns read int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels) { PHYSFS_file *ifile; short version; int id,len; int n_guns=0; ubyte model_buf[MODEL_BUF_SIZE]; if ((ifile=PHYSFSX_openReadBuffered(filename))==NULL) Error("Can't open file <%s>",filename); Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE); Pof_addr = 0; Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile)); PHYSFS_close(ifile); id = pof_read_int(model_buf); if (id!=0x4f505350) /* 'OPSP' */ Error("Bad ID in model file <%s>",filename); version = pof_read_short(model_buf); Assert(version >= 7); //must be 7 or higher for this data if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION) Error("Bad version (%d) in model file <%s>",version,filename); while (new_pof_read_int(id,model_buf) == 1) { id = INTEL_INT(id); //id = pof_read_int(model_buf); len = pof_read_int(model_buf); if (id == ID_GUNS) { //List of guns on this object int i; n_guns = pof_read_int(model_buf); for (i=0;i",filename); pof_read_vecs(&gun_points[id],1,model_buf); pof_read_vecs(&gun_dirs[id],1,model_buf); } } else pof_cfseek(model_buf,len,SEEK_CUR); } return n_guns; } //free up a model, getting rid of all its memory void free_model(polymodel *po) { d_free(po->model_data); } grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES]; bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES]; //draw a polygon model void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,g3s_lrgb light,fix *glow_values,bitmap_index alt_textures[]) { polymodel *po; int i; if (model_num < 0) return; Assert(model_num < N_polygon_models); po=&Polygon_models[model_num]; //check if should use simple model if (po->simpler_model ) //must have a simpler model if (flags==0) //can't switch if this is debris //!!if (!alt_textures) { //alternate textures might not match //alt textures might not match, but in the one case we're using this //for on 11/14/94, they do match. So we leave it in. { int cnt=1; fix depth; depth = g3_calc_point_depth(pos); //gets 3d depth while (po->simpler_model && depth > cnt++ * Simple_model_threshhold_scale * po->rad) po = &Polygon_models[po->simpler_model-1]; } if (alt_textures) for (i=0;in_textures;i++) { texture_list_index[i] = alt_textures[i]; texture_list[i] = &GameBitmaps[alt_textures[i].index]; } else for (i=0;in_textures;i++) { texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]]; texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index]; } // Make sure the textures for this object are paged in... piggy_page_flushed = 0; for (i=0;in_textures;i++) PIGGY_PAGE_IN( texture_list_index[i] ); // Hmmm... cache got flushed in the middle of paging all these in, // so we need to reread them all in. if (piggy_page_flushed) { piggy_page_flushed = 0; for (i=0;in_textures;i++) PIGGY_PAGE_IN( texture_list_index[i] ); } // Make sure that they can all fit in memory. Assert( piggy_page_flushed == 0 ); g3_start_instance_matrix(pos,orient); g3_set_interp_points(robot_points); if (flags == 0) //draw entire object g3_draw_polygon_model(po->model_data,texture_list,anim_angles,light,glow_values); else { int i; for (i=0;flags;flags>>=1,i++) if (flags & 1) { vms_vector ofs; Assert(i < po->n_models); //if submodel, rotate around its center point, not pivot point vm_vec_avg(&ofs,&po->submodel_mins[i],&po->submodel_maxs[i]); vm_vec_negate(&ofs); g3_start_instance_matrix(&ofs,NULL); g3_draw_polygon_model(&po->model_data[po->submodel_ptrs[i]],texture_list,anim_angles,light,glow_values); g3_done_instance(); } } g3_done_instance(); } void free_polygon_models() { int i; for (i=0;imins; big_mx = &pm->maxs; for (m=0;mn_models;m++) { vms_vector *mn,*mx,*ofs; mn = &pm->submodel_mins[m]; mx = &pm->submodel_maxs[m]; ofs= &pm->submodel_offsets[m]; data = (ushort *)&pm->model_data[pm->submodel_ptrs[m]]; type = *data++; Assert(type == 7 || type == 1); nverts = *data++; if (type==7) data+=2; //skip start & pad vp = (vms_vector *) data; *mn = *mx = *vp++; nverts--; if (m==0) *big_mn = *big_mx = *mn; while (nverts--) { if (vp->x > mx->x) mx->x = vp->x; if (vp->y > mx->y) mx->y = vp->y; if (vp->z > mx->z) mx->z = vp->z; if (vp->x < mn->x) mn->x = vp->x; if (vp->y < mn->y) mn->y = vp->y; if (vp->z < mn->z) mn->z = vp->z; if (vp->x+ofs->x > big_mx->x) big_mx->x = vp->x+ofs->x; if (vp->y+ofs->y > big_mx->y) big_mx->y = vp->y+ofs->y; if (vp->z+ofs->z > big_mx->z) big_mx->z = vp->z+ofs->z; if (vp->x+ofs->x < big_mn->x) big_mn->x = vp->x+ofs->x; if (vp->y+ofs->y < big_mn->y) big_mn->y = vp->y+ofs->y; if (vp->z+ofs->z < big_mn->z) big_mn->z = vp->z+ofs->z; vp++; } } } char Pof_names[MAX_POLYGON_MODELS][13]; //returns the number of this model #ifndef DRIVE int load_polygon_model(char *filename,int n_textures,int first_texture,robot_info *r) #else int load_polygon_model(char *filename,int n_textures,grs_bitmap ***textures) #endif { #ifdef DRIVE #define r NULL #endif Assert(N_polygon_models < MAX_POLYGON_MODELS); Assert(n_textures < MAX_POLYOBJ_TEXTURES); Assert(strlen(filename) <= 12); strcpy(Pof_names[N_polygon_models],filename); read_model_file(&Polygon_models[N_polygon_models],filename,r); polyobj_find_min_max(&Polygon_models[N_polygon_models]); g3_init_polygon_model(Polygon_models[N_polygon_models].model_data); if (highest_texture_num+1 != n_textures) Error("Model <%s> references %d textures but specifies %d.",filename,highest_texture_num+1,n_textures); Polygon_models[N_polygon_models].n_textures = n_textures; Polygon_models[N_polygon_models].first_texture = first_texture; Polygon_models[N_polygon_models].simpler_model = 0; // Assert(polygon_models[N_polygon_models]!=NULL); N_polygon_models++; return N_polygon_models-1; } void init_polygon_models() { N_polygon_models = 0; } //compare against this size when figuring how far to place eye for picture #define BASE_MODEL_SIZE 0x28000 #define DEFAULT_VIEW_DIST 0x60000 //draws the given model in the current canvas. The distance is set to //more-or-less fill the canvas. Note that this routine actually renders //into an off-screen canvas that it creates, then copies to the current //canvas. void draw_model_picture(int mn,vms_angvec *orient_angles) { vms_vector temp_pos=ZERO_VECTOR; vms_matrix temp_orient = IDENTITY_MATRIX; g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; Assert(mn>=0 && mnmodel_data = d_malloc(pm->model_data_size); Assert(pm->model_data != NULL); PHYSFS_read(fp, pm->model_data, sizeof(ubyte), pm->model_data_size); #ifdef WORDS_NEED_ALIGNMENT align_polygon_model_data(pm); #endif #ifdef WORDS_BIGENDIAN swap_polygon_model_data(pm->model_data); #endif } dxx-rebirth-0.58.1-d1x/main/polyobj.h000066400000000000000000000106701217717257200173310ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for polyobj.c, the polygon object code * */ #ifndef _POLYOBJ_H #define _POLYOBJ_H #include "vecmat.h" #include "gr.h" #include "3d.h" #ifndef DRIVE #include "robot.h" #endif #include "piggy.h" #ifndef DRIVE #define MAX_POLYGON_MODELS 85 #define MAX_SUBMODELS 10 #else #define MAX_POLYGON_MODELS 300 #define MAX_SUBMODELS 10 #endif //used to describe a polygon model typedef struct polymodel { int n_models; int model_data_size; ubyte *model_data; int submodel_ptrs[MAX_SUBMODELS]; vms_vector submodel_offsets[MAX_SUBMODELS]; vms_vector submodel_norms[MAX_SUBMODELS]; // norm for sep plane vms_vector submodel_pnts[MAX_SUBMODELS]; // point on sep plane fix submodel_rads[MAX_SUBMODELS]; // radius for each submodel ubyte submodel_parents[MAX_SUBMODELS]; // what is parent for each submodel vms_vector submodel_mins[MAX_SUBMODELS]; vms_vector submodel_maxs[MAX_SUBMODELS]; vms_vector mins,maxs; // min,max for whole model fix rad; ubyte n_textures; ushort first_texture; ubyte simpler_model; // alternate model with less detail (0 if none, model_num+1 else) //vms_vector min,max; } __pack__ polymodel; // array of pointers to polygon objects extern polymodel Polygon_models[]; // how many polygon objects there are extern int N_polygon_models; // array of names of currently-loaded models extern char Pof_names[MAX_POLYGON_MODELS][13]; void free_polygon_models(); void init_polygon_models(); #ifndef DRIVE int load_polygon_model(char *filename,int n_textures,int first_texture,robot_info *r); #else int load_polygon_model(char *filename,int n_textures,grs_bitmap ***textures); #endif // draw a polygon model void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,g3s_lrgb light,fix *glow_values,bitmap_index alt_textures[]); // fills in arrays gun_points & gun_dirs, returns the number of guns read int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels); // draws the given model in the current canvas. The distance is set to // more-or-less fill the canvas. Note that this routine actually renders // into an off-screen canvas that it creates, then copies to the current // canvas. void draw_model_picture(int mn,vms_angvec *orient_angles); #define MAX_POLYOBJ_TEXTURES 50 extern grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES]; extern bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES]; extern g3s_point robot_points[]; #ifdef WORDS_NEED_ALIGNMENT /* * A chunk struct (as used for alignment) contains all relevant data * concerning a piece of data that may need to be aligned. * To align it, we need to copy it to an aligned position, * and update all pointers to it. * (Those pointers are actually offsets * relative to start of model_data) to it. */ typedef struct chunk { ubyte *old_base; // where the offset sets off from (relative to beginning of model_data) ubyte *new_base; // where the base is in the aligned structure short offset; // how much to add to base to get the address of the offset short correction; // how much the value of the offset must be shifted for alignment } chunk; #define MAX_CHUNKS 100 // increase if insufficent /* * finds what chunks the data points to, adds them to the chunk_list, * and returns the length of the current chunk */ int get_chunks(ubyte *data, ubyte *new_data, chunk *list, int *no); #endif //def WORDS_NEED_ALIGNMENT /* * reads n polymodel structs from a PHYSFS_file */ extern int polymodel_read_n(polymodel *pm, int n, PHYSFS_file *fp); /* * routine which allocates, reads, and inits a polymodel's model_data */ extern void polygon_model_data_read(polymodel *pm, PHYSFS_file *fp); #endif dxx-rebirth-0.58.1-d1x/main/powerup.c000066400000000000000000000336411217717257200173520ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code for powerup objects. * */ #include #include #include #include "3d.h" #include "inferno.h" #include "object.h" #include "game.h" #include "fireball.h" #include "powerup.h" #include "gauges.h" #include "sounds.h" #include "player.h" #include "wall.h" #include "text.h" #include "weapon.h" #include "laser.h" #include "scores.h" #include "multi.h" #include "newdemo.h" #ifdef EDITOR #include "gr.h" // for powerup outline drawing #include "editor/editor.h" #endif int N_powerup_types = 0; powerup_type_info Powerup_info[MAX_POWERUP_TYPES]; int powerup_start_level[MAX_POWERUP_TYPES]; //process this powerup for this frame void do_powerup_frame(object *obj) { vclip_info *vci = &obj->rtype.vclip_info; vclip *vc = &Vclip[vci->vclip_num]; vci->frametime -= FrameTime; while (vci->frametime < 0 ) { vci->frametime += vc->frame_time; vci->framenum++; if (vci->framenum >= vc->num_frames) vci->framenum=0; } if (obj->lifeleft <= 0) { object_create_explosion(obj->segnum, &obj->pos, fl2f(3.5), VCLIP_POWERUP_DISAPPEARANCE ); if ( Vclip[VCLIP_POWERUP_DISAPPEARANCE].sound_num > -1 ) digi_link_sound_to_object( Vclip[VCLIP_POWERUP_DISAPPEARANCE].sound_num, obj-Objects, 0, F1_0); } } #ifdef EDITOR extern fix blob_vertices[]; // blob_vertices has 3 vertices in it, 4th must be computed void draw_blob_outline(void) { fix v3x, v3y; v3x = blob_vertices[4] - blob_vertices[2] + blob_vertices[0]; v3y = blob_vertices[5] - blob_vertices[3] + blob_vertices[1]; gr_setcolor(BM_XRGB(63, 63, 63)); gr_line(blob_vertices[0], blob_vertices[1], blob_vertices[2], blob_vertices[3]); gr_line(blob_vertices[2], blob_vertices[3], blob_vertices[4], blob_vertices[5]); gr_line(blob_vertices[4], blob_vertices[5], v3x, v3y); gr_line(v3x, v3y, blob_vertices[0], blob_vertices[1]); } #endif void draw_powerup(object *obj) { #ifdef EDITOR blob_vertices[0] = 0x80000; #endif draw_object_blob(obj, Vclip[obj->rtype.vclip_info.vclip_num].frames[obj->rtype.vclip_info.framenum] ); #ifdef EDITOR if (EditorWindow && (Cur_object_index == obj-Objects)) if (blob_vertices[0] != 0x80000) draw_blob_outline(); #endif } void powerup_basic(int redadd, int greenadd, int blueadd, int score, char *format, ...) { va_list args; va_start(args, format ); HUD_init_message_va(HM_DEFAULT, format, args); va_end(args); PALETTE_FLASH_ADD(redadd,greenadd,blueadd); add_points_to_score(score); } //#ifndef RELEASE // Give the megawow powerup! void do_megawow_powerup(int quantity) { int i; powerup_basic(30, 0, 30, 1, "MEGA-WOWIE-ZOWIE!"); #ifndef SHAREWARE Players[Player_num].primary_weapon_flags = 0xff; Players[Player_num].secondary_weapon_flags = 0xff; #else Players[Player_num].primary_weapon_flags = 0xff ^ (HAS_PLASMA_FLAG | HAS_FUSION_FLAG); Players[Player_num].secondary_weapon_flags = 0xff ^ (HAS_SMART_FLAG | HAS_MEGA_FLAG); #endif for (i=0; i<3; i++) Players[Player_num].primary_ammo[i] = 200; for (i=0; i<3; i++) Players[Player_num].secondary_ammo[i] = quantity; #ifndef SHAREWARE for (i=3; i<5; i++) Players[Player_num].primary_ammo[i] = 200; for (i=3; i<5; i++) Players[Player_num].secondary_ammo[i] = quantity/5; #endif if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_laser_level(Players[Player_num].laser_level, MAX_LASER_LEVEL); Players[Player_num].energy = F1_0*200; Players[Player_num].shields = F1_0*200; Players[Player_num].flags |= PLAYER_FLAGS_QUAD_LASERS; Players[Player_num].laser_level = MAX_LASER_LEVEL; update_laser_weapon_info(); } //#endif int pick_up_energy(void) { int used=0; if (Players[Player_num].energy < MAX_ENERGY) { Players[Player_num].energy += 3*F1_0 + 3*F1_0*(NDL - Difficulty_level); if (Players[Player_num].energy > MAX_ENERGY) Players[Player_num].energy = MAX_ENERGY; powerup_basic(15,15,7, ENERGY_SCORE, "%s %s %d",TXT_ENERGY,TXT_BOOSTED_TO,f2ir(Players[Player_num].energy)); used=1; } else HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, TXT_MAXED_OUT,TXT_ENERGY); return used; } int pick_up_vulcan_ammo(void) { int used=0; //added/killed on 1/21/99 by Victor Rachels ... how is this wrong? //-killed- int pwsave = Primary_weapon; // Ugh, save selected primary weapon around the picking up of the ammo. I apologize for this code. Matthew A. Toschlog if (pick_up_ammo(CLASS_PRIMARY, VULCAN_INDEX, VULCAN_AMMO_AMOUNT)) { powerup_basic(7, 14, 21, VULCAN_AMMO_SCORE, "%s!", TXT_VULCAN_AMMO); used = 1; } else { HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, "%s %d %s!",TXT_ALREADY_HAVE,f2i(VULCAN_AMMO_SCALE * Primary_ammo_max[VULCAN_INDEX]),TXT_VULCAN_ROUNDS); used = 0; } //-killed- Primary_weapon = pwsave; //end this section kill - VR return used; } // returns true if powerup consumed int do_powerup(object *obj) { int used=0; int vulcan_ammo_to_add_with_cannon; if ((Player_is_dead) || (ConsoleObject->type == OBJ_GHOST) || (Players[Player_num].shields < 0)) return 0; if (Game_mode & GM_MULTI) { /* * The fact: Collecting a powerup is decided Client-side and due to PING it takes time for other players to know if one collected a powerup actually. This may lead to the case two players collect the same powerup! * The solution: Let us check if someone else is closer to a powerup and if so, do not collect it. * NOTE: Player positions computed by 'shortpos' and PING can still cause a small margin of error. */ int i = 0; vms_vector tvec; fix mydist = vm_vec_normalized_dir(&tvec, &obj->pos, &ConsoleObject->pos); for (i = 0; i < MAX_PLAYERS; i++) { if (i == Player_num || Players[i].connected != CONNECT_PLAYING) continue; if (Objects[Players[i].objnum].type == OBJ_GHOST || Players[i].shields < 0) continue; if (mydist > vm_vec_normalized_dir(&tvec, &obj->pos, &Objects[Players[i].objnum].pos)) return 0; } } switch (obj->id) { case POW_EXTRA_LIFE: Players[Player_num].lives++; powerup_basic(15, 15, 15, 0, TXT_EXTRA_LIFE); used=1; break; case POW_ENERGY: used = pick_up_energy(); break; case POW_SHIELD_BOOST: if (Players[Player_num].shields < MAX_SHIELDS) { Players[Player_num].shields += 3*F1_0 + 3*F1_0*(NDL - Difficulty_level); if (Players[Player_num].shields > MAX_SHIELDS) Players[Player_num].shields = MAX_SHIELDS; powerup_basic(0, 0, 15, SHIELD_SCORE, "%s %s %d",TXT_SHIELD,TXT_BOOSTED_TO,f2ir(Players[Player_num].shields)); used=1; } else HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, TXT_MAXED_OUT,TXT_SHIELD); break; case POW_LASER: if (Players[Player_num].laser_level >= MAX_LASER_LEVEL) { Players[Player_num].laser_level = MAX_LASER_LEVEL; HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, TXT_MAXED_OUT,TXT_LASER); } else { if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_laser_level(Players[Player_num].laser_level, Players[Player_num].laser_level + 1); Players[Player_num].laser_level++; powerup_basic(10, 0, 10, LASER_SCORE, "%s %s %d",TXT_LASER,TXT_BOOSTED_TO, Players[Player_num].laser_level+1); update_laser_weapon_info(); pick_up_primary (LASER_INDEX); used=1; } if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_energy(); break; case POW_MISSILE_1: used=pick_up_secondary(CONCUSSION_INDEX,1); break; case POW_MISSILE_4: used=pick_up_secondary(CONCUSSION_INDEX,4); break; case POW_KEY_BLUE: if (Players[Player_num].flags & PLAYER_FLAGS_BLUE_KEY) break; #ifdef NETWORK multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0); #endif digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 ); Players[Player_num].flags |= PLAYER_FLAGS_BLUE_KEY; powerup_basic(0, 0, 15, KEY_SCORE, "%s %s",TXT_BLUE,TXT_ACCESS_GRANTED); if (Game_mode & GM_MULTI) used=0; else used=1; break; case POW_KEY_RED: if (Players[Player_num].flags & PLAYER_FLAGS_RED_KEY) break; #ifdef NETWORK multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0); #endif digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 ); Players[Player_num].flags |= PLAYER_FLAGS_RED_KEY; powerup_basic(15, 0, 0, KEY_SCORE, "%s %s",TXT_RED,TXT_ACCESS_GRANTED); if (Game_mode & GM_MULTI) used=0; else used=1; break; case POW_KEY_GOLD: if (Players[Player_num].flags & PLAYER_FLAGS_GOLD_KEY) break; #ifdef NETWORK multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0); #endif digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 ); Players[Player_num].flags |= PLAYER_FLAGS_GOLD_KEY; powerup_basic(15, 15, 7, KEY_SCORE, "%s %s",TXT_YELLOW,TXT_ACCESS_GRANTED); if (Game_mode & GM_MULTI) used=0; else used=1; break; case POW_QUAD_FIRE: if (!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) { Players[Player_num].flags |= PLAYER_FLAGS_QUAD_LASERS; powerup_basic(15, 15, 7, QUAD_FIRE_SCORE, "%s!",TXT_QUAD_LASERS); update_laser_weapon_info(); used=1; } else HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, "%s %s!",TXT_ALREADY_HAVE,TXT_QUAD_LASERS); if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_energy(); break; case POW_VULCAN_WEAPON: if ((used = pick_up_primary(VULCAN_INDEX)) != 0) { vulcan_ammo_to_add_with_cannon = obj->ctype.powerup_info.count; if (vulcan_ammo_to_add_with_cannon < VULCAN_WEAPON_AMMO_AMOUNT) vulcan_ammo_to_add_with_cannon = VULCAN_WEAPON_AMMO_AMOUNT; pick_up_ammo(CLASS_PRIMARY, VULCAN_INDEX, vulcan_ammo_to_add_with_cannon); } //added/edited 8/3/98 by Victor Rachels to fix vulcan multi bug //check if multi, if so, pick up ammo w/o using, set ammo left. else, normal //killed 8/27/98 by Victor Rachels to fix vulcan ammo multiplying. new way // is by spewing the current held ammo when dead. //-killed if (!used && (Game_mode & GM_MULTI)) //-killed { //-killed int tempcount; //-killed tempcount=Players[Player_num].primary_ammo[VULCAN_INDEX]; //-killed if (pick_up_ammo(CLASS_PRIMARY, VULCAN_INDEX, obj->ctype.powerup_info.count)) //-killed obj->ctype.powerup_info.count -= Players[Player_num].primary_ammo[VULCAN_INDEX]-tempcount; //-killed } //end kill - Victor Rachels if (!used && !(Game_mode & GM_MULTI) ) //end addition/edit - Victor Rachels used = pick_up_vulcan_ammo(); break; case POW_SPREADFIRE_WEAPON: used = pick_up_primary(SPREADFIRE_INDEX); if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_energy(); break; case POW_PLASMA_WEAPON: used = pick_up_primary(PLASMA_INDEX); if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_energy(); break; case POW_FUSION_WEAPON: used = pick_up_primary(FUSION_INDEX); if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_energy(); break; case POW_PROXIMITY_WEAPON: used=pick_up_secondary(PROXIMITY_INDEX,4); break; case POW_SMARTBOMB_WEAPON: used=pick_up_secondary(SMART_INDEX,1); break; case POW_MEGA_WEAPON: used=pick_up_secondary(MEGA_INDEX,1); break; case POW_VULCAN_AMMO: { used = pick_up_vulcan_ammo(); if (!used && !(Game_mode & GM_MULTI) ) used = pick_up_vulcan_ammo(); break; } break; case POW_HOMING_AMMO_1: used=pick_up_secondary(HOMING_INDEX,1); break; case POW_HOMING_AMMO_4: used=pick_up_secondary(HOMING_INDEX,4); break; case POW_CLOAK: if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, "%s %s!",TXT_ALREADY_ARE,TXT_CLOAKED); break; } else { Players[Player_num].cloak_time = GameTime64; Players[Player_num].flags |= PLAYER_FLAGS_CLOAKED; ai_do_cloak_stuff(); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_cloak(); #endif powerup_basic(-10,-10,-10, CLOAK_SCORE, "%s!",TXT_CLOAKING_DEVICE); used = 1; break; } case POW_INVULNERABILITY: if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE) { HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, "%s %s!",TXT_ALREADY_ARE,TXT_INVULNERABLE); break; } else { Players[Player_num].invulnerable_time = GameTime64; Players[Player_num].flags |= PLAYER_FLAGS_INVULNERABLE; powerup_basic(7, 14, 21, INVULNERABILITY_SCORE, "%s!",TXT_INVULNERABILITY); used = 1; break; } #ifndef RELEASE case POW_MEGAWOW: do_megawow_powerup(50); used = 1; break; #endif default: break; } //always say used, until physics problem (getting stuck on unused powerup) //is solved. Note also the break statements above that are commented out //!! used=1; if (used && Powerup_info[obj->id].hit_sound > -1 ) { #ifdef NETWORK if (Game_mode & GM_MULTI) // Added by Rob, take this out if it turns out to be not good for net games! multi_send_play_sound(Powerup_info[obj->id].hit_sound, F1_0); #endif digi_play_sample( Powerup_info[obj->id].hit_sound, F1_0 ); } return used; } /* * reads n powerup_type_info structs from a PHYSFS_file */ int powerup_type_info_read_n(powerup_type_info *pti, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) { pti[i].vclip_num = PHYSFSX_readInt(fp); pti[i].hit_sound = PHYSFSX_readInt(fp); pti[i].size = PHYSFSX_readFix(fp); pti[i].light = PHYSFSX_readFix(fp); } return i; } dxx-rebirth-0.58.1-d1x/main/powerup.h000066400000000000000000000063441217717257200173570ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Powerup header file. * */ #ifndef _POWERUP_H #define _POWERUP_H #include "vclip.h" #include "player.h" enum powerup_type_t { POW_EXTRA_LIFE = 0, POW_ENERGY = 1, POW_SHIELD_BOOST = 2, POW_LASER = 3, POW_KEY_BLUE = 4, POW_KEY_RED = 5, POW_KEY_GOLD = 6, POW_RADAR_ROBOTS = 7, POW_RADAR_POWERUPS = 8, POW_FULL_MAP = 9, POW_MISSILE_1 = 10, POW_MISSILE_4 = 11, // 4-pack MUST follow single missile POW_QUAD_FIRE = 12, POW_VULCAN_WEAPON = 13, POW_SPREADFIRE_WEAPON = 14, POW_PLASMA_WEAPON = 15, POW_FUSION_WEAPON = 16, POW_PROXIMITY_WEAPON = 17, POW_HOMING_AMMO_1 = 18, POW_HOMING_AMMO_4 = 19, POW_SMARTBOMB_WEAPON = 20, POW_MEGA_WEAPON = 21, POW_VULCAN_AMMO = 22, POW_CLOAK = 23, POW_TURBO = 24, POW_INVULNERABILITY = 25, POW_HEADLIGHT = 26, POW_MEGAWOW = 27, }; #define VULCAN_AMMO_MAX (392*2) #define VULCAN_WEAPON_AMMO_AMOUNT 196 #define VULCAN_AMMO_AMOUNT (49*2) // What I picked up What it said I picked up // ---------------- ------------------------ // vulcan ammo 4 homing missiles // mega missile 1 homing missile // smart missile vulcan ammo // 4 homing missiles mega missile // 1 homing missile smart missile // // The rest were correct. I can help you with this whenever you're free. #define MAX_POWERUP_TYPES 29 #define POWERUP_NAME_LENGTH 16 // Length of a robot or powerup name. extern char Powerup_names[MAX_POWERUP_TYPES][POWERUP_NAME_LENGTH]; typedef struct powerup_type_info { int vclip_num; int hit_sound; fix size; // 3d size of longest dimension fix light; // amount of light cast by this powerup, set in bitmaps.tbl } __pack__ powerup_type_info; extern int N_powerup_types; extern powerup_type_info Powerup_info[MAX_POWERUP_TYPES]; void draw_powerup(object *obj); //returns true if powerup consumed int do_powerup(object *obj); //process (animate) a powerup for one frame void do_powerup_frame(object *obj); // Diminish shields and energy towards max in case they exceeded it. extern void diminish_towards_max(void); extern void do_megawow_powerup(int quantity); extern void powerup_basic(int redadd, int greenadd, int blueadd, int score, char *format, ...); // may this powerup be added to the level? // returns number of powerups left if true, otherwise 0. extern int may_create_powerup(int powerup); /* * reads n powerup_type_info structs from a PHYSFS_file */ extern int powerup_type_info_read_n(powerup_type_info *pti, int n, PHYSFS_file *fp); #endif /* _POWERUP_H */ dxx-rebirth-0.58.1-d1x/main/render.c000066400000000000000000001451611217717257200171310ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Rendering Stuff * */ #include #include #include #include #include "inferno.h" #include "segment.h" #include "dxxerror.h" #include "bm.h" #include "texmap.h" #include "render.h" #include "game.h" #include "object.h" #include "laser.h" #include "textures.h" #include "screens.h" #include "segpoint.h" #include "wall.h" #include "texmerge.h" #include "physics.h" #include "3d.h" #include "gameseg.h" #include "vclip.h" #include "lighting.h" #include "cntrlcen.h" #include "newdemo.h" #include "automap.h" #include "endlevel.h" #include "key.h" #include "newmenu.h" #include "u_mem.h" #include "piggy.h" #include "timer.h" #include "effects.h" #include "playsave.h" #ifdef OGL #include "ogl_init.h" #endif #include "args.h" #define INITIAL_LOCAL_LIGHT (F1_0/4) // local light value in segment of occurence (of light emission) #ifdef EDITOR #include "editor/editor.h" #include "editor/esegment.h" #endif // (former) "detail level" values #ifdef OGL int Render_depth = MAX_RENDER_SEGS; //how many segments deep to render #else int Render_depth = 20; //how many segments deep to render #endif int Max_perspective_depth = 8; // Deepest segment at which perspective interpolation will be used. int Max_linear_depth = 50; // Deepest segment at which linear interpolation will be used. int Max_linear_depth_objects = 20; int Simple_model_threshhold_scale = 50; // switch to simpler model when the object has depth greater than this value times its radius. int Max_debris_objects = 15; // How many debris objects to create //used for checking if points have been rotated int Clear_window_color=-1; int Clear_window=2; // 1 = Clear whole background window, 2 = clear view portals into rest of world, 0 = no clear int framecount=-1; short Rotated_last[MAX_VERTICES]; // When any render function needs to know what's looking at it, it should // access Viewer members. object * Viewer = NULL; vms_vector Viewer_eye; //valid during render int N_render_segs; fix Render_zoom = 0x9000; //the player's zoom factor #ifndef NDEBUG ubyte object_rendered[MAX_OBJECTS]; #endif #ifdef EDITOR int Render_only_bottom=0; int Bottom_bitmap_num = 9; #endif #ifdef EDITOR int _search_mode = 0; //true if looking for curseg,side,face short _search_x,_search_y; //pixel we're looking at int found_seg,found_side,found_face,found_poly; #else #define _search_mode 0 #endif #if defined(NDEBUG) && !defined(EDITOR) //if no debug code, set these vars to constants #define Outline_mode 0 #define Show_only_curside 0 #else int Outline_mode=0,Show_only_curside=0; int toggle_outline_mode(void) { return Outline_mode = !Outline_mode; } int toggle_show_only_curside(void) { return Show_only_curside = !Show_only_curside; } void draw_outline(int nverts,g3s_point **pointlist) { int i; gr_setcolor(BM_XRGB(63,63,63)); for (i=0;i 10 ) //whiting out return; // flash_ang += fixmul(FLASH_CYCLE_RATE,FrameTime); flash_ang += fixmul(flash_rate,FrameTime); fix_fastsincos(flash_ang,&flash_scale,NULL); flash_scale = (flash_scale + f1_0)/2; } #ifdef OGL extern int Current_level_num; #endif // ----------------------------------------------------------------------------------- // Render a face. // It would be nice to not have to pass in segnum and sidenum, but they are used for our // hideously hacked in headlight system. // vp is a pointer to vertex ids. // tmap1, tmap2 are texture map ids. tmap2 is the pasty one. void render_face(int segnum, int sidenum, int nv, int *vp, int tmap1, int tmap2, uvl *uvlp, vms_vector *norm) { grs_bitmap *bm; #ifdef OGL grs_bitmap *bm2 = NULL; #endif g3s_uvl uvl_copy[8]; g3s_lrgb dyn_light[8]; int i; g3s_point *pointlist[8]; Assert(nv <= 8); for (i=0; i= NumTextures) { Int3(); Segments[segnum].sides[sidenum].tmap_num = 0; } #ifdef OGL if (GameArg.DbgAltTexMerge){ PIGGY_PAGE_IN(Textures[tmap1]); bm = &GameBitmaps[Textures[tmap1].index]; if (tmap2){ PIGGY_PAGE_IN(Textures[tmap2&0x3FFF]); bm2 = &GameBitmaps[Textures[tmap2&0x3FFF].index]; } if (bm2 && (bm2->bm_flags&BM_FLAG_SUPER_TRANSPARENT)){ bm = texmerge_get_cached_bitmap( tmap1, tmap2 ); bm2 = NULL; } }else #endif // New code for overlapping textures... if (tmap2 != 0) { bm = texmerge_get_cached_bitmap( tmap1, tmap2 ); } else { bm = &GameBitmaps[Textures[tmap1].index]; PIGGY_PAGE_IN(Textures[tmap1]); } Assert( !(bm->bm_flags & BM_FLAG_PAGED_OUT) ); //set light values for each vertex & build pointlist for (i=0;i MAX_LIGHT) uvl_copy[i].l = MAX_LIGHT; // And now the same for the ACTUAL (rgb) light we want to use //scale static light for destruction effect if (Control_center_destroyed) //make lights flash { if (PlayerCfg.DynLightColor) // let the mine glow red a little { dyn_light[i].r = fixmul(flash_scale>=f0_5*1.5?flash_scale:f0_5*1.5,uvl_copy[i].l); dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l); } else dyn_light[i].r = dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l); } // add light color dyn_light[i].r += Dynamic_light[vp[i]].r; dyn_light[i].g += Dynamic_light[vp[i]].g; dyn_light[i].b += Dynamic_light[vp[i]].b; // saturate at max value if (dyn_light[i].r > MAX_LIGHT) dyn_light[i].r = MAX_LIGHT; if (dyn_light[i].g > MAX_LIGHT) dyn_light[i].g = MAX_LIGHT; if (dyn_light[i].b > MAX_LIGHT) dyn_light[i].b = MAX_LIGHT; if (PlayerCfg.AlphaEffects) // due to additive blending, transparent sprites will become invivible in font of white surfaces (lamps). Fix that with a little desaturation { dyn_light[i].r *= .93; dyn_light[i].g *= .93; dyn_light[i].b *= .93; } } if ( PlayerCfg.AlphaEffects && ( TmapInfo[tmap1].eclip_num == ECLIP_NUM_FUELCEN ) ) // set nice transparency/blending for some special effects (if we do more, we should maybe use switch here) gr_settransblend(GR_FADE_OFF, GR_BLEND_ADDITIVE_C); #ifdef EDITOR if ((Render_only_bottom) && (sidenum == WBOTTOM)) { g3_draw_tmap(nv,pointlist,uvl_copy,dyn_light,&GameBitmaps[Textures[Bottom_bitmap_num].index]); } else #endif { #ifdef OGL if (bm2) { g3_draw_tmap_2(nv,pointlist,uvl_copy,dyn_light,bm,bm2,((tmap2&0xC000)>>14) & 3); } else #endif { g3_draw_tmap(nv,pointlist,uvl_copy,dyn_light,bm); } } gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); // revert any transparency/blending setting back to normal #ifndef NDEBUG if (Outline_mode) draw_outline(nv, pointlist); #endif } #ifdef EDITOR // ----------------------------------------------------------------------------------- // Only called if editor active. // Used to determine which face was clicked on. void check_face(int segnum, int sidenum, int facenum, int nv, int *vp, int tmap1, int tmap2, uvl *uvlp) { int i; if (_search_mode) { int save_lighting; #ifndef OGL grs_bitmap *bm; #endif g3s_uvl uvl_copy[8]; g3s_lrgb dyn_light[8]; g3s_point *pointlist[4]; memset(dyn_light, 0, sizeof(dyn_light)); #ifndef OGL if (tmap2 > 0 ) bm = texmerge_get_cached_bitmap( tmap1, tmap2 ); else bm = &GameBitmaps[Textures[tmap1].index]; #endif for (i=0; icv_bitmap,_search_x,_search_y) == 1) { found_seg = segnum; found_side = sidenum; found_face = facenum; } } } #endif fix Tulate_min_dot = (F1_0/4); //--unused-- fix Tulate_min_ratio = (2*F1_0); fix Min_n0_n1_dot = (F1_0*15/16); // ----------------------------------------------------------------------------------- // Render a side. // Check for normal facing. If so, render faces on side dictated by sidep->type. void render_side(segment *segp, int sidenum) { int vertnum_list[4]; side *sidep = &segp->sides[sidenum]; vms_vector tvec; fix v_dot_n0, v_dot_n1; uvl temp_uvls[3]; fix min_dot, max_dot; vms_vector normals[2]; if (!(WALL_IS_DOORWAY(segp,sidenum) & WID_RENDER_FLAG)) //if (WALL_IS_DOORWAY(segp, sidenum) == WID_NO_WALL) return; #ifdef COMPACT_SEGS get_side_normals(segp, sidenum, &normals[0], &normals[1] ); #else normals[0] = segp->sides[sidenum].normals[0]; normals[1] = segp->sides[sidenum].normals[1]; #endif // Regardless of whether this side is comprised of a single quad, or two triangles, we need to know one normal, so // deal with it, get the dot product. if (sidep->type == SIDE_IS_TRI_13) { vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][1]]]); } else { vm_vec_normalized_dir(&tvec, &Viewer_eye, &Vertices[segp->verts[Side_to_verts[sidenum][0]]]); } get_side_verts(vertnum_list,segp-Segments,sidenum); v_dot_n0 = vm_vec_dot(&tvec, &normals[0]); if (sidep->type == SIDE_IS_QUAD) { if (v_dot_n0 >= 0) { render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]); #ifdef EDITOR check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } } else { // Although this side has been triangulated, because it is not planar, see if it is acceptable // to render it as a single quadrilateral. This is a function of how far away the viewer is, how non-planar // the face is, how normal to the surfaces the view is. // Now, if both dot products are close to 1.0, then render two triangles as a single quad. v_dot_n1 = vm_vec_dot(&tvec, &normals[1]); if (v_dot_n0 < v_dot_n1) { min_dot = v_dot_n0; max_dot = v_dot_n1; } else { min_dot = v_dot_n1; max_dot = v_dot_n0; } // Determine whether to detriangulate side: (speed hack, assumes Tulate_min_ratio == F1_0*2, should fixmul(min_dot, Tulate_min_ratio)) if (DETRIANGULATION && ((min_dot+F1_0/256 > max_dot) || ((Viewer->segnum != segp-Segments) && (min_dot > Tulate_min_dot) && (max_dot < min_dot*2)))) { fix n0_dot_n1; // The other detriangulation code doesn't deal well with badly non-planar sides. n0_dot_n1 = vm_vec_dot(&normals[0], &normals[1]); if (n0_dot_n1 < Min_n0_n1_dot) { goto im_so_ashamed; } render_face(segp-Segments, sidenum, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]); #ifdef EDITOR check_face(segp-Segments, sidenum, 0, 4, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } else { im_so_ashamed: ; if (sidep->type == SIDE_IS_TRI_02) { if (v_dot_n0 >= 0) { render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls, &normals[0]); #ifdef EDITOR check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } if (v_dot_n1 >= 0) { temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[2]; temp_uvls[2] = sidep->uvls[3]; vertnum_list[1] = vertnum_list[2]; vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0, 2, 3 on side render_face(segp-Segments, sidenum, 3, &vertnum_list[0], sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[1]); #ifdef EDITOR check_face(segp-Segments, sidenum, 1, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } } else if (sidep->type == SIDE_IS_TRI_13) { if (v_dot_n1 >= 0) { render_face(segp-Segments, sidenum, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, &sidep->uvls[1], &normals[1]); // rendering 1,2,3, so just skip 0 #ifdef EDITOR check_face(segp-Segments, sidenum, 1, 3, &vertnum_list[1], sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } if (v_dot_n0 >= 0) { temp_uvls[0] = sidep->uvls[0]; temp_uvls[1] = sidep->uvls[1]; temp_uvls[2] = sidep->uvls[3]; vertnum_list[2] = vertnum_list[3]; // want to render from vertices 0,1,3 render_face(segp-Segments, sidenum, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, temp_uvls, &normals[0]); #ifdef EDITOR check_face(segp-Segments, sidenum, 0, 3, vertnum_list, sidep->tmap_num, sidep->tmap_num2, sidep->uvls); #endif } } else Error("Illegal side type in render_side, type = %i, segment # = %i, side # = %i\n", sidep->type,(int)(segp-Segments), sidenum); } } } #ifdef EDITOR void render_object_search(object *obj) { int changed=0; //note that we draw each pixel object twice, since we cannot control //what color the object draws in, so we try color 0, then color 1, //in case the object itself is rendering color 0 gr_setcolor(0); //set our search pixel to color zero #ifdef OGL ogl_end_frame(); // For OpenGL we use gr_rect instead of gr_pixel, // because in some implementations (like my Macbook Pro 5,1) // point smoothing can't be turned off. // Point smoothing would change the pixel to dark grey, but it MUST be black. // Making a 3x3 rectangle wouldn't matter // (but it only seems to draw a single pixel anyway) gr_rect(_search_x - 1, _search_y - 1, _search_x + 1, _search_y + 1); ogl_start_frame(); #else gr_pixel(_search_x,_search_y); #endif render_object(obj); if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 0) changed=1; gr_setcolor(1); #ifdef OGL ogl_end_frame(); gr_rect(_search_x - 1, _search_y - 1, _search_x + 1, _search_y + 1); ogl_start_frame(); #else gr_pixel(_search_x,_search_y); #endif render_object(obj); if (gr_ugpixel(&grd_curcanv->cv_bitmap,_search_x,_search_y) != 1) changed=1; if (changed) { if (obj->segnum != -1) Cursegp = &Segments[obj->segnum]; found_seg = -(obj-Objects+1); } } #endif void do_render_object(int objnum) { #ifdef EDITOR int save_3d_outline=0; #endif object *obj = &Objects[objnum]; int count = 0; int n; Assert(objnum < MAX_OBJECTS); #ifndef NDEBUG if (object_rendered[objnum]) { //already rendered this... /* Int3(); */ //get Matt!!! return; } object_rendered[objnum] = 1; #endif // Added by MK on 09/07/94 (at about 5:28 pm, CDT, on a beautiful, sunny late summer day!) so // that the guided missile system will know what objects to look at. if ((Objects[objnum].type == OBJ_ROBOT) || (Objects[objnum].type == OBJ_PLAYER)) { //Assert(Num_rendered_objects < MAX_RENDERED_OBJECTS); // This peculiar piece of code makes us keep track of the most recently rendered objects, which // are probably the higher priority objects, without overflowing the buffer if (Num_rendered_objects >= MAX_RENDERED_OBJECTS) { Int3(); Num_rendered_objects /= 2; } Ordered_rendered_object_list[Num_rendered_objects++] = objnum; } if ((count++ > MAX_OBJECTS) || (obj->next == objnum)) { Int3(); // infinite loop detected obj->next = -1; // won't this clean things up? return; // get out of this infinite loop! } //g3_draw_object(obj->class_id,&obj->pos,&obj->orient,obj->size); //check for editor object #ifdef EDITOR if (EditorWindow && objnum==Cur_object_index) { save_3d_outline = g3d_interp_outline; g3d_interp_outline=1; } #endif #ifdef EDITOR if (_search_mode) render_object_search(obj); else #endif //NOTE LINK TO ABOVE render_object(obj); for (n=obj->attached_obj;n!=-1;n=Objects[n].ctype.expl_info.next_attach) { Assert(Objects[n].type == OBJ_FIREBALL); Assert(Objects[n].control_type == CT_EXPLOSION); Assert(Objects[n].flags & OF_ATTACHED); render_object(&Objects[n]); } #ifdef EDITOR if (EditorWindow && objnum==Cur_object_index) g3d_interp_outline = save_3d_outline; #endif } #ifndef NDEBUG int draw_boxes=0; int window_check=1,draw_edges=0,new_seg_sorting=1,pre_draw_segs=0; int no_migrate_segs=1,migrate_objects=1,behind_check=1; int check_window_check=0; #else #define draw_boxes 0 #define window_check 1 #define draw_edges 0 #define new_seg_sorting 1 #define pre_draw_segs 0 #define no_migrate_segs 1 #define migrate_objects 1 #define behind_check 1 #define check_window_check 0 #endif //increment counter for checking if points rotated //This must be called at the start of the frame if rotate_list() will be used void render_start_frame() { framecount++; if (framecount==0) { //wrap! memset(Rotated_last,0,sizeof(Rotated_last)); //clear all to zero framecount=1; //and set this frame to 1 } } //Given a lit of point numbers, rotate any that haven't been rotated this frame g3s_codes rotate_list(int nv,int *pointnumlist) { int i,pnum; g3s_point *pnt; g3s_codes cc; cc.uand = 0xff; cc.uor = 0; for (i=0;ip3_codes; cc.uor |= pnt->p3_codes; } return cc; } //Given a lit of point numbers, project any that haven't been projected void project_list(int nv,int *pointnumlist) { int i,pnum; for (i=0;iverts); if (! cc.uand) { //all off screen? Automap_visited[segnum]=1; for (sn=0; snobjects;objnum!=-1;objnum=Objects[objnum].next) do_render_object(objnum); } #endif } // ----- This used to be called when Show_only_curside was set. // ----- It is wholly and superiorly replaced by render_side. // -- //render one side of one segment // -- void render_seg_side(segment *seg,int _side) // -- { // -- g3s_codes cc; // -- short vertnum_list[4]; // -- // -- cc=g3_rotate_list(8,&seg->verts); // -- // -- if (! cc.uand) { //all off screen? // -- int fn,pn,i; // -- side *s; // -- face *f; // -- poly *p; // -- // -- s=&seg->sides[_side]; // -- // -- for (f=s->faces,fn=s->num_faces;fn;fn--,f++) // -- for (p=f->polys,pn=f->num_polys;pn;pn--,p++) { // -- grs_bitmap *tmap; // -- // -- for (i=0;inum_vertices;i++) vertnum_list[i] = seg->verts[p->verts[i]]; // -- // -- if (p->tmap_num >= NumTextures) { // -- Warning("Invalid tmap number %d, NumTextures=%d\n...Changing in poly structure to tmap 0",p->tmap_num,NumTextures); // -- p->tmap_num = 0; //change it permanantly // -- } // -- // -- tmap = Textures[p->tmap_num]; // -- // -- g3_check_and_draw_tmap(p->num_vertices,vertnum_list,(g3s_uvl *) &p->uvls,tmap,&f->normal); // -- // -- if (Outline_mode) draw_outline(p->num_vertices,vertnum_list); // -- } // -- } // -- // -- } #define CROSS_WIDTH i2f(8) #define CROSS_HEIGHT i2f(8) #if !defined(NDEBUG) || defined(EDITOR) //draw outline for curside void outline_seg_side(segment *seg,int _side,int edge,int vert) { g3s_codes cc; cc=rotate_list(8,seg->verts); if (! cc.uand) { //all off screen? g3s_point *pnt; //render curedge of curside of curseg in green gr_setcolor(BM_XRGB(0,63,0)); g3_draw_line(&Segment_points[seg->verts[Side_to_verts[_side][edge]]],&Segment_points[seg->verts[Side_to_verts[_side][(edge+1)%4]]]); //draw a little cross at the current vert pnt = &Segment_points[seg->verts[Side_to_verts[_side][vert]]]; g3_project_point(pnt); //make sure projected // gr_setcolor(BM_XRGB(0,0,63)); // gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy); // gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT); gr_line(pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT); gr_line(pnt->p3_sx,pnt->p3_sy-CROSS_HEIGHT,pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy); gr_line(pnt->p3_sx+CROSS_WIDTH,pnt->p3_sy,pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT); gr_line(pnt->p3_sx,pnt->p3_sy+CROSS_HEIGHT,pnt->p3_sx-CROSS_WIDTH,pnt->p3_sy); } } #endif #if 0 //this stuff could probably just be deleted #define DEFAULT_PERSPECTIVE_DEPTH 6 int Perspective_depth=DEFAULT_PERSPECTIVE_DEPTH; //how many levels deep to render in perspective int inc_perspective_depth(void) { return ++Perspective_depth; } int dec_perspective_depth(void) { return Perspective_depth==1?Perspective_depth:--Perspective_depth; } int reset_perspective_depth(void) { return Perspective_depth = DEFAULT_PERSPECTIVE_DEPTH; } #endif typedef struct rect { short left,top,right,bot; } rect; ubyte code_window_point(fix x,fix y,rect *w) { ubyte code=0; if (x <= w->left) code |= 1; if (x >= w->right) code |= 2; if (y <= w->top) code |= 4; if (y >= w->bot) code |= 8; return code; } #ifndef NDEBUG void draw_window_box(int color,short left,short top,short right,short bot) { short l,t,r,b; gr_setcolor(color); l=left; t=top; r=right; b=bot; if ( r<0 || b<0 || l>=grd_curcanv->cv_bitmap.bm_w || (t>=grd_curcanv->cv_bitmap.bm_h && b>=grd_curcanv->cv_bitmap.bm_h)) return; if (l<0) l=0; if (t<0) t=0; if (r>=grd_curcanv->cv_bitmap.bm_w) r=grd_curcanv->cv_bitmap.bm_w-1; if (b>=grd_curcanv->cv_bitmap.bm_h) b=grd_curcanv->cv_bitmap.bm_h-1; gr_line(i2f(l),i2f(t),i2f(r),i2f(t)); gr_line(i2f(r),i2f(t),i2f(r),i2f(b)); gr_line(i2f(r),i2f(b),i2f(l),i2f(b)); gr_line(i2f(l),i2f(b),i2f(l),i2f(t)); } #endif int matt_find_connect_side(int seg0,int seg1); #ifndef NDEBUG char visited2[MAX_SEGMENTS]; #endif unsigned char visited[MAX_SEGMENTS]; short Render_list[MAX_RENDER_SEGS]; short Seg_depth[MAX_RENDER_SEGS]; //depth for each seg in Render_list ubyte processed[MAX_RENDER_SEGS]; //whether each entry has been processed int lcnt_save,scnt_save; //@@short *persp_ptr; short render_pos[MAX_SEGMENTS]; //where in render_list does this segment appear? //ubyte no_render_flag[MAX_RENDER_SEGS]; rect render_windows[MAX_RENDER_SEGS]; short render_obj_list[MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS][OBJS_PER_SEG]; //for objects #define RED BM_XRGB(63,0,0) #define WHITE BM_XRGB(63,63,63) //Global vars for window clip test int Window_clip_left,Window_clip_top,Window_clip_right,Window_clip_bot; //Given two sides of segment, tell the two verts which form the //edge between them int Two_sides_to_edge[6][6][2] = { { {-1,-1}, {3,7}, {-1,-1}, {2,6}, {6,7}, {2,3} }, { {3,7}, {-1,-1}, {0,4}, {-1,-1}, {4,7}, {0,3} }, { {-1,-1}, {0,4}, {-1,-1}, {1,5}, {4,5}, {0,1} }, { {2,6}, {-1,-1}, {1,5}, {-1,-1}, {5,6}, {1,2} }, { {6,7}, {4,7}, {4,5}, {5,6}, {-1,-1}, {-1,-1} }, { {2,3}, {0,3}, {0,1}, {1,2}, {-1,-1}, {-1,-1} } }; //given an edge specified by two verts, give the two sides on that edge int Edge_to_sides[8][8][2] = { { {-1,-1}, {2,5}, {-1,-1}, {1,5}, {1,2}, {-1,-1}, {-1,-1}, {-1,-1} }, { {2,5}, {-1,-1}, {3,5}, {-1,-1}, {-1,-1}, {2,3}, {-1,-1}, {-1,-1} }, { {-1,-1}, {3,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {0,3}, {-1,-1} }, { {1,5}, {-1,-1}, {0,5}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {0,1} }, { {1,2}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {1,4} }, { {-1,-1}, {2,3}, {-1,-1}, {-1,-1}, {2,4}, {-1,-1}, {3,4}, {-1,-1} }, { {-1,-1}, {-1,-1}, {0,3}, {-1,-1}, {-1,-1}, {3,4}, {-1,-1}, {0,4} }, { {-1,-1}, {-1,-1}, {-1,-1}, {0,1}, {1,4}, {-1,-1}, {0,4}, {-1,-1} }, }; //@@//perform simple check on tables //@@check_check() //@@{ //@@ int i,j; //@@ //@@ for (i=0;i<8;i++) //@@ for (j=0;j<8;j++) //@@ Assert(Edge_to_sides[i][j][0] == Edge_to_sides[j][i][0] && //@@ Edge_to_sides[i][j][1] == Edge_to_sides[j][i][1]); //@@ //@@ for (i=0;i<6;i++) //@@ for (j=0;j<6;j++) //@@ Assert(Two_sides_to_edge[i][j][0] == Two_sides_to_edge[j][i][0] && //@@ Two_sides_to_edge[i][j][1] == Two_sides_to_edge[j][i][1]); //@@ //@@ //@@} //given an edge, tell what side is on that edge int find_seg_side(segment *seg,int *verts,int notside) { int i; int vv0=-1,vv1=-1; int side0,side1; int *eptr; int v0,v1; int *vp; //@@ check_check(); v0 = verts[0]; v1 = verts[1]; vp = seg->verts; for (i=0; i<8; i++) { int svv = *vp++; // seg->verts[i]; if (vv0==-1 && svv == v0) { vv0 = i; if (vv1 != -1) break; } if (vv1==-1 && svv == v1) { vv1 = i; if (vv0 != -1) break; } } if (vv0 == -1 || vv1 == -1) return -1; eptr = Edge_to_sides[vv0][vv1]; side0 = eptr[0]; side1 = eptr[1]; Assert(side0!=-1 && side1!=-1); if (side0 != notside) { Assert(side1==notside); return side0; } else { Assert(side0==notside); return side1; } } //find the two segments that join a given seg though two sides, and //the sides of those segments the abut. int find_joining_side_norms(vms_vector *norm0_0,vms_vector *norm0_1,vms_vector *norm1_0,vms_vector *norm1_1,vms_vector **pnt0,vms_vector **pnt1,segment *seg,int s0,int s1) { segment *seg0,*seg1; int edge_verts[2]; int notside0,notside1; int edgeside0,edgeside1; Assert(s0!=-1 && s1!=-1); seg0 = &Segments[seg->children[s0]]; seg1 = &Segments[seg->children[s1]]; edge_verts[0] = seg->verts[Two_sides_to_edge[s0][s1][0]]; edge_verts[1] = seg->verts[Two_sides_to_edge[s0][s1][1]]; Assert(edge_verts[0]!=-1 && edge_verts[1]!=-1); notside0 = find_connect_side(seg,seg0); Assert(notside0 != -1); notside1 = find_connect_side(seg,seg1); Assert(notside1 != -1); edgeside0 = find_seg_side(seg0,edge_verts,notside0); if (edgeside0 == -1) return 0; edgeside1 = find_seg_side(seg1,edge_verts,notside1); if (edgeside1 == -1) return 0; //deal with the case where an edge is shared by more than two segments //@@ if (IS_CHILD(seg0->children[edgeside0])) { //@@ segment *seg00; //@@ int notside00; //@@ //@@ seg00 = &Segments[seg0->children[edgeside0]]; //@@ //@@ if (seg00 != seg1) { //@@ //@@ notside00 = find_connect_side(seg0,seg00); //@@ Assert(notside00 != -1); //@@ //@@ edgeside0 = find_seg_side(seg00,edge_verts,notside00); //@@ seg0 = seg00; //@@ } //@@ //@@ } //@@ //@@ if (IS_CHILD(seg1->children[edgeside1])) { //@@ segment *seg11; //@@ int notside11; //@@ //@@ seg11 = &Segments[seg1->children[edgeside1]]; //@@ //@@ if (seg11 != seg0) { //@@ notside11 = find_connect_side(seg1,seg11); //@@ Assert(notside11 != -1); //@@ //@@ edgeside1 = find_seg_side(seg11,edge_verts,notside11); //@@ seg1 = seg11; //@@ } //@@ } // if ( IS_CHILD(seg0->children[edgeside0]) || // IS_CHILD(seg1->children[edgeside1])) // return 0; #ifdef COMPACT_SEGS get_side_normals(seg0, edgeside0, norm0_0, norm0_1 ); get_side_normals(seg1, edgeside1, norm1_0, norm1_1 ); #else *norm0_0 = seg0->sides[edgeside0].normals[0]; *norm0_1 = seg0->sides[edgeside0].normals[1]; *norm1_0 = seg1->sides[edgeside1].normals[0]; *norm1_1 = seg1->sides[edgeside1].normals[1]; #endif *pnt0 = &Vertices[seg0->verts[Side_to_verts[edgeside0][seg0->sides[edgeside0].type==3?1:0]]]; *pnt1 = &Vertices[seg1->verts[Side_to_verts[edgeside1][seg1->sides[edgeside1].type==3?1:0]]]; return 1; } //see if the order matters for these two children. //returns 0 if order doesn't matter, 1 if c0 before c1, -1 if c1 before c0 int compare_children(segment *seg,short c0,short c1) { vms_vector norm0_0,norm0_1,*pnt0,temp; vms_vector norm1_0,norm1_1,*pnt1; fix d0_0,d0_1,d1_0,d1_1,d0,d1; int t; if (Side_opposite[c0] == c1) return 0; Assert(c0!=-1 && c1!=-1); //find normals of adjoining sides t = find_joining_side_norms(&norm0_0,&norm0_1,&norm1_0,&norm1_1,&pnt0,&pnt1,seg,c0,c1); if (!t) // can happen - 4D rooms! return 0; vm_vec_sub(&temp,&Viewer_eye,pnt0); d0_0 = vm_vec_dot(&norm0_0,&temp); d0_1 = vm_vec_dot(&norm0_1,&temp); vm_vec_sub(&temp,&Viewer_eye,pnt1); d1_0 = vm_vec_dot(&norm1_0,&temp); d1_1 = vm_vec_dot(&norm1_1,&temp); d0 = (d0_0 < 0 || d0_1 < 0)?-1:1; d1 = (d1_0 < 0 || d1_1 < 0)?-1:1; if (d0 < 0 && d1 < 0) return 0; if (d0 < 0) return 1; else if (d1 < 0) return -1; else return 0; } int ssc_total=0,ssc_swaps=0; //short the children of segment to render in the correct order //returns non-zero if swaps were made int sort_seg_children(segment *seg,int n_children,short *child_list) { int i,j; int r; int made_swaps,count; if (n_children == 0) return 0; ssc_total++; //for each child, compare with other children and see if order matters //if order matters, fix if wrong count = 0; do { made_swaps = 0; for (i=0;i= 0;i++); Assert(i < OBJS_PER_SEG); marker = render_obj_list[checkn][i]; if (marker != -1) { checkn = -marker; //Assert(checkn < MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS); if (checkn >= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) { Int3(); return; } } } while (marker != -1); //now we have found a slot. put object in it if (i != OBJS_PER_SEG-1) { render_obj_list[checkn][i] = objnum; render_obj_list[checkn][i+1] = -1; } else { //chain to additional list int lookn; //find an available sublist for (lookn=MAX_RENDER_SEGS;render_obj_list[lookn][0]!=-1 && lookn= MAX_RENDER_SEGS+N_EXTRA_OBJ_LISTS) { Int3(); return; } render_obj_list[checkn][i] = -lookn; render_obj_list[lookn][0] = objnum; render_obj_list[lookn][1] = -1; } } #define SORT_LIST_SIZE 50 typedef struct sort_item { int objnum; fix dist; } sort_item; sort_item sort_list[SORT_LIST_SIZE]; int n_sort_items; //compare function for object sort. int sort_func(sort_item *a,sort_item *b) { fix delta_dist; // object *obj_a,*obj_b; delta_dist = a->dist - b->dist; return delta_dist; //return distance } void build_object_lists(int n_segs) { int nn; for (nn=0;nnnext) { int new_segnum,did_migrate,list_pos; obj = &Objects[objnum]; if (obj->type == OBJ_NONE) continue; Assert( obj->segnum == segnum ); if (obj->flags & OF_ATTACHED) continue; //ignore this object new_segnum = segnum; list_pos = nn; if (obj->type != OBJ_CNTRLCEN) //don't migrate controlcen do { segmasks m; did_migrate = 0; m = get_seg_masks(&obj->pos, new_segnum, obj->size, __FILE__, __LINE__); if (m.sidemask) { int sn,sf; for (sn=0,sf=1;sn<6;sn++,sf<<=1) if (m.sidemask & sf) { segment *seg = &Segments[obj->segnum]; if (WALL_IS_DOORWAY(seg,sn) & WID_FLY_FLAG) { //can explosion migrate through int child = seg->children[sn]; int checknp; for (checknp=list_pos;checknp--;) if (Render_list[checknp] == child) { new_segnum = child; list_pos = checknp; did_migrate = 1; } } } } } while (did_migrate); add_obj_to_seglist(objnum,list_pos); } } } //now that there's a list for each segment, sort the items in those lists for (nn=0;nn0) if (t<0) {lookn = -t; i=0;} else render_obj_list[lookn][i++] = sort_list[--n].objnum; render_obj_list[lookn][i] = -1; //mark (possibly new) end } } } int Use_player_head_angles = 0; vms_angvec Player_head_angles; extern int Num_tmaps_drawn; extern int Total_pixels; //--unused-- int Total_num_tmaps_drawn=0; int Rear_view=0; void start_lighting_frame(object *viewer); #ifdef JOHN_ZOOM fix Zoom_factor=F1_0; #endif //renders onto current canvas void render_frame(fix eye_offset) { int start_seg_num; if (Endlevel_sequence) { render_endlevel_frame(eye_offset); return; } if ( Newdemo_state == ND_STATE_RECORDING ) { if (eye_offset >= 0 ) { newdemo_record_start_frame(FrameTime ); newdemo_record_viewer_object(Viewer); } } start_lighting_frame(Viewer); //this is for ugly light-smoothing hack g3_start_frame(); Viewer_eye = Viewer->pos; // if (Viewer->type == OBJ_PLAYER && (PlayerCfg.CockpitMode[1]!=CM_REAR_VIEW)) // vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4); if (eye_offset) { vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset); } #ifdef EDITOR if (EditorWindow) Viewer_eye = Viewer->pos; #endif start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum); if (start_seg_num==-1) start_seg_num = Viewer->segnum; if (Rear_view && (Viewer==ConsoleObject)) { vms_matrix headm,viewm; Player_head_angles.p = Player_head_angles.b = 0; Player_head_angles.h = 0x7fff; vm_angles_2_matrix(&headm,&Player_head_angles); vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm); g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom); } else { #ifdef JOHN_ZOOM if (keyd_pressed[KEY_RSHIFT] ) { Zoom_factor += FrameTime*4; if (Zoom_factor > F1_0*5 ) Zoom_factor=F1_0*5; } else { Zoom_factor -= FrameTime*4; if (Zoom_factor < F1_0 ) Zoom_factor = F1_0; } g3_set_view_matrix(&Viewer_eye,&Viewer->orient,fixdiv(Render_zoom,Zoom_factor)); #else g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom); #endif } if (Clear_window == 1) { if (Clear_window_color == -1) Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7); gr_clear_canvas(Clear_window_color); } render_mine(start_seg_num,eye_offset); g3_end_frame(); } int first_terminal_seg; //build a list of segments to be rendered //fills in Render_list & N_render_segs void build_segment_list(int start_seg_num) { int lcnt,scnt,ecnt; int l,c; int ch; memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1)); memset(render_pos, -1, sizeof(render_pos[0])*(Highest_segment_index+1)); //memset(no_render_flag, 0, sizeof(no_render_flag[0])*(MAX_RENDER_SEGS)); memset(processed, 0, sizeof(processed)); #ifndef NDEBUG memset(visited2, 0, sizeof(visited2[0])*(Highest_segment_index+1)); #endif lcnt = scnt = 0; Render_list[lcnt] = start_seg_num; visited[start_seg_num]=1; Seg_depth[lcnt] = 0; lcnt++; ecnt = lcnt; render_pos[start_seg_num] = 0; #ifndef NDEBUG if (pre_draw_segs) render_segment(start_seg_num); #endif render_windows[0].left=render_windows[0].top=0; render_windows[0].right=grd_curcanv->cv_bitmap.bm_w-1; render_windows[0].bot=grd_curcanv->cv_bitmap.bm_h-1; //breadth-first renderer //build list for (l=0;lleft,check_w->top,check_w->right,check_w->bot); #endif if (segnum == -1) continue; seg = &Segments[segnum]; rotated=0; //look at all sides of this segment. //tricky code to look at sides in correct order follows for (c=n_children=0;cchildren[c]; if ( (window_check || !visited[ch]) && (wid & WID_RENDPAST_FLAG) ) { if (behind_check) { sbyte *sv = Side_to_verts[c]; ubyte codes_and=0xff; int i; rotate_list(8,seg->verts); rotated=1; for (i=0;i<4;i++) codes_and &= Segment_points[seg->verts[sv[i]]].p3_codes; if (codes_and & CC_BEHIND) continue; } child_list[n_children++] = c; } } //now order the sides in some magical way if (new_seg_sorting) sort_seg_children(seg,n_children,child_list); //for (c=0;cchildren[c]; for (c=0;cchildren[siden]; //if ( (window_check || !visited[ch])&& (WALL_IS_DOORWAY(seg, c))) { { if (window_check) { int i; ubyte codes_and_3d,codes_and_2d; short _x,_y,min_x=32767,max_x=-32767,min_y=32767,max_y=-32767; int no_proj_flag=0; //a point wasn't projected if (rotated<2) { if (!rotated) rotate_list(8,seg->verts); project_list(8,seg->verts); rotated=2; } for (i=0,codes_and_3d=codes_and_2d=0xff;i<4;i++) { int p = seg->verts[Side_to_verts[siden][i]]; g3s_point *pnt = &Segment_points[p]; if (! (pnt->p3_flags&PF_PROJECTED)) {no_proj_flag=1; break;} _x = f2i(pnt->p3_sx); _y = f2i(pnt->p3_sy); codes_and_3d &= pnt->p3_codes; codes_and_2d &= code_window_point(_x,_y,check_w); #ifndef NDEBUG if (draw_edges) { gr_setcolor(BM_XRGB(31,0,31)); gr_line(pnt->p3_sx,pnt->p3_sy, Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sx, Segment_points[seg->verts[Side_to_verts[siden][(i+1)%4]]].p3_sy); } #endif if (_x < min_x) min_x = _x; if (_x > max_x) max_x = _x; if (_y < min_y) min_y = _y; if (_y > max_y) max_y = _y; } #ifndef NDEBUG if (draw_boxes) draw_window_box(WHITE,min_x,min_y,max_x,max_y); #endif if (no_proj_flag || (!codes_and_3d && !codes_and_2d)) { //maybe add this segment int rp = render_pos[ch]; rect *new_w = &render_windows[lcnt]; if (no_proj_flag) *new_w = *check_w; else { new_w->left = max(check_w->left,min_x); new_w->right = min(check_w->right,max_x); new_w->top = max(check_w->top,min_y); new_w->bot = min(check_w->bot,max_y); } //see if this seg already visited, and if so, does current window //expand the old window? if (rp != -1) { if (new_w->left < render_windows[rp].left || new_w->top < render_windows[rp].top || new_w->right > render_windows[rp].right || new_w->bot > render_windows[rp].bot) { new_w->left = min(new_w->left,render_windows[rp].left); new_w->right = max(new_w->right,render_windows[rp].right); new_w->top = min(new_w->top,render_windows[rp].top); new_w->bot = max(new_w->bot,render_windows[rp].bot); if (no_migrate_segs) { //no_render_flag[lcnt] = 1; Render_list[lcnt] = -1; render_windows[rp] = *new_w; //get updated window processed[rp] = 0; //force reprocess goto no_add; } else Render_list[rp]=-1; } else goto no_add; } #ifndef NDEBUG if (draw_boxes) draw_window_box(5,new_w->left,new_w->top,new_w->right,new_w->bot); #endif render_pos[ch] = lcnt; Render_list[lcnt] = ch; Seg_depth[lcnt] = l; lcnt++; if (lcnt >= MAX_RENDER_SEGS) {goto done_list;} visited[ch] = 1; #ifndef NDEBUG if (pre_draw_segs) render_segment(ch); #endif no_add: ; } } else { Render_list[lcnt] = ch; Seg_depth[lcnt] = l; lcnt++; if (lcnt >= MAX_RENDER_SEGS) {goto done_list;} visited[ch] = 1; } } } } scnt = ecnt; ecnt = lcnt; } done_list: lcnt_save = lcnt; scnt_save = scnt; first_terminal_seg = scnt; N_render_segs = lcnt; } //renders onto current canvas void render_mine(int start_seg_num,fix eye_offset) { int nn; //moved 9/2/98 by Victor Rachels to remove warning/unused var #ifndef NDEBUG int i; for (i=0;i<=Highest_object_index;i++) object_rendered[i] = 0; #endif //end move - Victor Rachels // Initialize number of objects (actually, robots!) rendered this frame. Num_rendered_objects = 0; //set up for rendering render_start_frame(); #if defined(EDITOR) && !defined(NDEUBG) if (Show_only_curside) { rotate_list(8,Cursegp->verts); render_side(Cursegp,Curside); goto done_rendering; } #endif #ifdef EDITOR if (_search_mode || eye_offset>0) { //lcnt = lcnt_save; //scnt = scnt_save; } else #endif //NOTE LINK TO ABOVE!! build_segment_list(start_seg_num); //fills in Render_list & N_render_segs //render away #ifndef NDEBUG if (!window_check) { Window_clip_left = Window_clip_top = 0; Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1; Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1; } #endif #ifndef NDEBUG if (!(_search_mode || eye_offset>0)) { int i; for (i=0;i0) && migrate_objects) if (!(_search_mode)) build_object_lists(N_render_segs); if (eye_offset<=0) // Do for left eye or zero. set_dynamic_light(); if (!_search_mode && Clear_window == 2) { if (first_terminal_seg < N_render_segs) { int i; if (Clear_window_color == -1) Clear_window_color = BM_XRGB(0, 0, 0); //BM_XRGB(31, 15, 7); gr_setcolor(Clear_window_color); for (i=first_terminal_seg; i0 || (unsigned char)visited[segnum]!=255)) { //set global render window vars if (window_check) { Window_clip_left = render_windows[nn].left; Window_clip_top = render_windows[nn].top; Window_clip_right = render_windows[nn].right; Window_clip_bot = render_windows[nn].bot; } render_segment(segnum); visited[segnum]=255; if (window_check) { //reset for objects Window_clip_left = Window_clip_top = 0; Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1; Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1; } if (migrate_objects) { //int n_expl_objs=0,expl_objs[5],i; int listnum; int save_linear_depth = Max_linear_depth; Max_linear_depth = Max_linear_depth_objects; listnum = nn; for (objnp=0;render_obj_list[listnum][objnp]!=-1;) { int ObjNumber = render_obj_list[listnum][objnp]; if (ObjNumber >= 0) { do_render_object(ObjNumber); // note link to above else objnp++; } else { listnum = -ObjNumber; objnp = 0; } } Max_linear_depth = save_linear_depth; } } } #else // Sorting elements for Alpha - 3 passes // First Pass: render opaque level geometry + transculent level geometry with high Alpha-Test func for (nn=N_render_segs;nn--;) { int segnum; segnum = Render_list[nn]; Current_seg_depth = Seg_depth[nn]; if (segnum!=-1 && (_search_mode || eye_offset>0 || (unsigned char)visited[segnum]!=255)) { //set global render window vars if (window_check) { Window_clip_left = render_windows[nn].left; Window_clip_top = render_windows[nn].top; Window_clip_right = render_windows[nn].right; Window_clip_bot = render_windows[nn].bot; } // render segment { segment *seg = &Segments[segnum]; g3s_codes cc; int sn; Assert(segnum!=-1 && segnum<=Highest_segment_index); cc=rotate_list(8,seg->verts); if (! cc.uand) { //all off screen? if (Viewer->type!=OBJ_ROBOT) Automap_visited[segnum]=1; for (sn=0; sn0 || (unsigned char)visited[segnum]!=255)) { //set global render window vars if (window_check) { Window_clip_left = render_windows[nn].left; Window_clip_top = render_windows[nn].top; Window_clip_right = render_windows[nn].right; Window_clip_bot = render_windows[nn].bot; } visited[segnum]=255; if (window_check) { //reset for objects Window_clip_left = Window_clip_top = 0; Window_clip_right = grd_curcanv->cv_bitmap.bm_w-1; Window_clip_bot = grd_curcanv->cv_bitmap.bm_h-1; } // render objects { int listnum; int save_linear_depth = Max_linear_depth; Max_linear_depth = Max_linear_depth_objects; listnum = nn; for (objnp=0;render_obj_list[listnum][objnp]!=-1;) { int ObjNumber = render_obj_list[listnum][objnp]; if (ObjNumber >= 0) { do_render_object(ObjNumber); // note link to above else objnp++; } else { listnum = -ObjNumber; objnp = 0; } } Max_linear_depth = save_linear_depth; } } } memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1)); // Third Pass - Render Transculent level geometry with normal Alpha-Func for (nn=N_render_segs;nn--;) { int segnum; segnum = Render_list[nn]; Current_seg_depth = Seg_depth[nn]; if (segnum!=-1 && (_search_mode || eye_offset>0 || (unsigned char)visited[segnum]!=255)) { //set global render window vars if (window_check) { Window_clip_left = render_windows[nn].left; Window_clip_top = render_windows[nn].top; Window_clip_right = render_windows[nn].right; Window_clip_bot = render_windows[nn].bot; } // render segment { segment *seg = &Segments[segnum]; g3s_codes cc; int sn; Assert(segnum!=-1 && segnum<=Highest_segment_index); cc=rotate_list(8,seg->verts); if (! cc.uand) { //all off screen? if (Viewer->type!=OBJ_ROBOT) Automap_visited[segnum]=1; for (sn=0; snrender_type==RT_POLYOBJ || obj->render_type==RT_MORPH); Assert(obj->id < N_robot_types); r = &Robot_info[obj->id]; pm =&Polygon_models[r->model_num]; if (gun_num >= r->n_guns) { Int3(); gun_num = 0; } // Assert(gun_num < r->n_guns); pnt = r->gun_points[gun_num]; mn = r->gun_submodels[gun_num]; //instance up the tree for this gun while (mn != 0) { vms_vector tpnt; vm_angles_2_matrix(&m,&obj->rtype.pobj_info.anim_angles[mn]); vm_transpose_matrix(&m); vm_vec_rotate(&tpnt,&pnt,&m); vm_vec_add(&pnt,&tpnt,&pm->submodel_offsets[mn]); mn = pm->submodel_parents[mn]; } //now instance for the entire object vm_copy_transpose_matrix(&m,&obj->orient); vm_vec_rotate(gun_point,&pnt,&m); vm_vec_add2(gun_point,&obj->pos); } //fills in ptr to list of joints, and returns the number of joints in list //takes the robot type (object id), gun number, and desired state int robot_get_anim_state(const jointpos **jp_list_ptr,int robot_type,int gun_num,int state) { Assert(gun_num <= Robot_info[robot_type].n_guns); *jp_list_ptr = &Robot_joints[Robot_info[robot_type].anim_states[gun_num][state].offset]; return Robot_info[robot_type].anim_states[gun_num][state].n_joints; } //for test, set a robot to a specific state void set_robot_state(object *obj,int state) { int g,j,jo; robot_info *ri; jointlist *jl; Assert(obj->type == OBJ_ROBOT); ri = &Robot_info[obj->id]; for (g=0;gn_guns+1;g++) { jl = &ri->anim_states[g][state]; jo = jl->offset; for (j=0;jn_joints;j++,jo++) { int jn; jn = Robot_joints[jo].jointnum; obj->rtype.pobj_info.anim_angles[jn] = Robot_joints[jo].angles; } } } //set the animation angles for this robot. Gun fields of robot info must //be filled in. void robot_set_angles(robot_info *r,polymodel *pm,vms_angvec angs[N_ANIM_STATES][MAX_SUBMODELS]) { int m,g,state; int gun_nums[MAX_SUBMODELS]; //which gun each submodel is part of for (m=0;mn_models;m++) gun_nums[m] = r->n_guns; //assume part of body... gun_nums[0] = -1; //body never animates, at least for now for (g=0;gn_guns;g++) { m = r->gun_submodels[g]; while (m != 0) { gun_nums[m] = g; //...unless we find it in a gun m = pm->submodel_parents[m]; } } for (g=0;gn_guns+1;g++) { for (state=0;stateanim_states[g][state].n_joints = 0; r->anim_states[g][state].offset = N_robot_joints; for (m=0;mn_models;m++) { if (gun_nums[m] == g) { Robot_joints[N_robot_joints].jointnum = m; Robot_joints[N_robot_joints].angles = angs[state][m]; r->anim_states[g][state].n_joints++; N_robot_joints++; Assert(N_robot_joints < MAX_ROBOT_JOINTS); } } } } } /* * reads n jointlist structs from a PHYSFS_file */ static int jointlist_read_n(jointlist *jl, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) { jl[i].n_joints = PHYSFSX_readShort(fp); jl[i].offset = PHYSFSX_readShort(fp); } return i; } /* * reads n robot_info structs from a PHYSFS_file */ int robot_info_read_n(robot_info *ri, int n, PHYSFS_file *fp) { int i, j; for (i = 0; i < n; i++) { ri[i].model_num = PHYSFSX_readInt(fp); ri[i].n_guns = PHYSFSX_readInt(fp); for (j = 0; j < MAX_GUNS; j++) PHYSFSX_readVector(&ri[i].gun_points[j], fp); for (j = 0; j < MAX_GUNS; j++) ri[i].gun_submodels[j] = PHYSFSX_readByte(fp); ri[i].exp1_vclip_num = PHYSFSX_readShort(fp); ri[i].exp1_sound_num = PHYSFSX_readShort(fp); ri[i].exp2_vclip_num = PHYSFSX_readShort(fp); ri[i].exp2_sound_num = PHYSFSX_readShort(fp); ri[i].weapon_type = PHYSFSX_readShort(fp); ri[i].contains_id = PHYSFSX_readByte(fp); ri[i].contains_count = PHYSFSX_readByte(fp); ri[i].contains_prob = PHYSFSX_readByte(fp); ri[i].contains_type = PHYSFSX_readByte(fp); ri[i].score_value = PHYSFSX_readInt(fp); ri[i].lighting = PHYSFSX_readFix(fp); ri[i].strength = PHYSFSX_readFix(fp); ri[i].mass = PHYSFSX_readFix(fp); ri[i].drag = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri[i].field_of_view[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri[i].firing_wait[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri[i].turn_time[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri[i].max_speed[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) ri[i].circle_distance[j] = PHYSFSX_readFix(fp); for (j = 0; j < NDL; j++) PHYSFS_read(fp, &(ri[i].rapidfire_count[j]), sizeof(ubyte), 1); for (j = 0; j < NDL; j++) PHYSFS_read(fp, &(ri[i].evade_speed[j]), sizeof(ubyte), 1); ri[i].cloak_type = PHYSFSX_readByte(fp); ri[i].attack_type = PHYSFSX_readByte(fp); ri[i].boss_flag = PHYSFSX_readByte(fp); ri[i].see_sound = PHYSFSX_readByte(fp); ri[i].attack_sound = PHYSFSX_readByte(fp); ri[i].claw_sound = PHYSFSX_readByte(fp); for (j = 0; j < MAX_GUNS + 1; j++) jointlist_read_n(ri[i].anim_states[j], N_ANIM_STATES, fp); ri[i].always_0xabcd = PHYSFSX_readInt(fp); } return i; } /* * reads n jointpos structs from a PHYSFS_file */ int jointpos_read_n(jointpos *jp, int n, PHYSFS_file *fp) { int i; for (i = 0; i < n; i++) { jp[i].jointnum = PHYSFSX_readShort(fp); PHYSFSX_readAngleVec(&jp[i].angles, fp); } return i; } dxx-rebirth-0.58.1-d1x/main/robot.h000066400000000000000000000127111217717257200167760ustar00rootroot00000000000000/* * * Header for robot.c * */ #ifndef _ROBOT_H #define _ROBOT_H #include "vecmat.h" #include "game.h" struct object; #define MAX_GUNS 8 //should be multiple of 4 for ubyte array //Animation states #define AS_REST 0 #define AS_ALERT 1 #define AS_FIRE 2 #define AS_RECOIL 3 #define AS_FLINCH 4 #define N_ANIM_STATES 5 #define RI_CLOAKED_NEVER 0 #define RI_CLOAKED_ALWAYS 1 #define RI_CLOAKED_EXCEPT_FIRING 2 //describes the position of a certain joint typedef struct jointpos { short jointnum; vms_angvec angles; } __pack__ jointpos; //describes a list of joint positions typedef struct jointlist { short n_joints; short offset; } jointlist; // Robot information typedef struct robot_info { int model_num; // which polygon model? int n_guns; // how many different gun positions vms_vector gun_points[MAX_GUNS]; // where each gun model is ubyte gun_submodels[MAX_GUNS]; // which submodel is each gun in? short exp1_vclip_num; short exp1_sound_num; short exp2_vclip_num; short exp2_sound_num; short weapon_type; sbyte contains_id; // ID of powerup this robot can contain. sbyte contains_count; // Max number of things this instance can contain. sbyte contains_prob; // Probability that this instance will contain something in N/16 sbyte contains_type; // Type of thing contained, robot or powerup, in bitmaps.tbl, !0=robot, 0=powerup int score_value; // Score from this robot. fix lighting; // should this be here or with polygon model? fix strength; // Initial shields of robot fix mass; // how heavy is this thing? fix drag; // how much drag does it have? fix field_of_view[NDL]; // compare this value with forward_vector.dot.vector_to_player, if field_of_view <, then robot can see player fix firing_wait[NDL]; // time in seconds between shots fix turn_time[NDL]; // time in seconds to rotate 360 degrees in a dimension fix max_speed[NDL]; // maximum speed attainable by this robot fix circle_distance[NDL]; // distance at which robot circles player sbyte rapidfire_count[NDL]; // number of shots fired rapidly sbyte evade_speed[NDL]; // rate at which robot can evade shots, 0=none, 4=very fast sbyte cloak_type; // 0=never, 1=always, 2=except-when-firing sbyte attack_type; // 0=firing, 1=charge (like green guy) sbyte boss_flag; // 0 = not boss, 1 = boss. Is that surprising? ubyte see_sound; // sound robot makes when it first sees the player ubyte attack_sound; // sound robot makes when it attacks the player ubyte claw_sound; // sound robot makes as it claws you (attack_type should be 1) //animation info jointlist anim_states[MAX_GUNS+1][N_ANIM_STATES]; int always_0xabcd; // debugging } __pack__ robot_info; #define MAX_ROBOT_TYPES 30 // maximum number of robot types #define ROBOT_NAME_LENGTH 16 extern char Robot_names[MAX_ROBOT_TYPES][ROBOT_NAME_LENGTH]; //the array of robots types extern robot_info Robot_info[]; // Robot info for AI system, loaded from bitmaps.tbl. //how many kinds of robots extern int N_robot_types; // Number of robot types. We used to assume this was the same as N_polygon_models. //test data for one robot #define MAX_ROBOT_JOINTS 600 extern jointpos Robot_joints[MAX_ROBOT_JOINTS]; extern int N_robot_joints; //given an object and a gun number, return position in 3-space of gun //fills in gun_point void calc_gun_point(vms_vector *gun_point,struct object *obj,int gun_num); //void calc_gun_point(vms_vector *gun_point,int objnum,int gun_num); // Tells joint positions for a gun to be in a specified state. // A gun can have associated with it any number of joints. In order to tell whether a gun is a certain // state (such as FIRE or ALERT), you should call this function and check the returned joint positions // against the robot's gun's joint positions. This function should also be called to determine how to // move a gun into a desired position. // For now (May 30, 1994), it is assumed that guns will linearly interpolate from one joint position to another. // There is no ordering of joint movement, so it's impossible to guarantee that a strange starting position won't // cause a gun to move through a robot's body, for example. // Given: // jp_list_ptr pointer to list of joint angles, on exit, this is pointing at a static array // robot_type type of robot for which to get joint information. A particular type, not an instance of a robot. // gun_num gun number. If in 0..Robot_info[robot_type].n_guns-1, then it is a gun, else it refers to non-animating parts of robot. // state state about which to get information. Legal states in range 0..N_ANIM_STATES-1, defined in robot.h, are: // AS_REST, AS_ALERT, AS_FIRE, AS_RECOIL, AS_FLINCH // On exit: // Returns number of joints in list. // jp_list_ptr is stuffed with a pointer to a static array of joint positions. This pointer is valid forever. extern int robot_get_anim_state(const jointpos **jp_list_ptr,int robot_type,int gun_num,int state); /* * reads n robot_info structs from a PHYSFS_file */ extern int robot_info_read_n(robot_info *ri, int n, PHYSFS_file *fp); /* * reads n jointpos structs from a PHYSFS_file */ extern int jointpos_read_n(jointpos *jp, int n, PHYSFS_file *fp); #endif dxx-rebirth-0.58.1-d1x/main/scores.c000066400000000000000000000271311217717257200171440ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Inferno High Scores and Statistics System * */ #include #include #include #include #include "scores.h" #include "dxxerror.h" #include "pstypes.h" #include "window.h" #include "gr.h" #include "key.h" #include "mouse.h" #include "palette.h" #include "game.h" #include "gamefont.h" #include "u_mem.h" #include "newmenu.h" #include "menu.h" #include "player.h" #include "screens.h" #include "gamefont.h" #include "mouse.h" #include "joy.h" #include "timer.h" #include "text.h" #include "strutil.h" #include "rbaudio.h" #ifdef OGL #include "ogl_init.h" #endif #define VERSION_NUMBER 1 #define SCORES_FILENAME "descent.hi" #define COOL_MESSAGE_LEN 50 #define MAX_HIGH_SCORES 10 typedef struct stats_info { char name[CALLSIGN_LEN+1]; int score; sbyte starting_level; sbyte ending_level; sbyte diff_level; short kill_ratio; // 0-100 short hostage_ratio; // int seconds; // How long it took in seconds... } __pack__ stats_info; typedef struct all_scores { char signature[3]; // DHS sbyte version; // version char cool_saying[COOL_MESSAGE_LEN]; stats_info stats[MAX_HIGH_SCORES]; } __pack__ all_scores; void scores_read(all_scores *scores) { PHYSFS_file *fp; int fsize; // clear score array... memset( scores, 0, sizeof(all_scores) ); fp = PHYSFS_openRead(SCORES_FILENAME); if (fp==NULL) { int i; // No error message needed, code will work without a scores file sprintf( scores->cool_saying, "%s", TXT_REGISTER_DESCENT ); sprintf( scores->stats[0].name, "Parallax" ); sprintf( scores->stats[1].name, "Mike" ); sprintf( scores->stats[2].name, "Matt" ); sprintf( scores->stats[3].name, "John" ); sprintf( scores->stats[4].name, "Yuan" ); sprintf( scores->stats[5].name, "Adam" ); sprintf( scores->stats[6].name, "Mark" ); sprintf( scores->stats[7].name, "Allender" ); sprintf( scores->stats[8].name, "Jasen" ); sprintf( scores->stats[9].name, "Rob" ); for (i=0; i<10; i++) scores->stats[i].score = (10-i)*1000; return; } fsize = PHYSFS_fileLength(fp); if ( fsize != sizeof(all_scores) ) { PHYSFS_close(fp); return; } // Read 'em in... PHYSFS_read(fp, scores, sizeof(all_scores), 1); PHYSFS_close(fp); if ( (scores->version!=VERSION_NUMBER)||(scores->signature[0]!='D')||(scores->signature[1]!='H')||(scores->signature[2]!='S') ) { memset( scores, 0, sizeof(all_scores) ); return; } } void scores_write(all_scores *scores) { PHYSFS_file *fp; fp = PHYSFS_openWrite(SCORES_FILENAME); if (fp==NULL) { nm_messagebox( TXT_WARNING, 1, TXT_OK, "%s\n'%s'", TXT_UNABLE_TO_OPEN, SCORES_FILENAME ); return; } scores->signature[0]='D'; scores->signature[1]='H'; scores->signature[2]='S'; scores->version = VERSION_NUMBER; PHYSFS_write(fp, scores,sizeof(all_scores), 1); PHYSFS_close(fp); } void int_to_string( int number, char *dest ) { int i,l,c; char buffer[20],*p; sprintf( buffer, "%d", number ); l = strlen(buffer); if (l<=3) { // Don't bother with less than 3 digits sprintf( dest, "%d", number ); return; } c = 0; p=dest; for (i=l-1; i>=0; i-- ) { if (c==3) { *p++=','; c = 0; } c++; *p++ = buffer[i]; } *p++ = '\0'; d_strrev(dest); } void scores_fill_struct(stats_info * stats) { strcpy( stats->name, Players[Player_num].callsign ); stats->score = Players[Player_num].score; stats->ending_level = Players[Player_num].level; if (Players[Player_num].num_robots_total > 0 ) stats->kill_ratio = (Players[Player_num].num_kills_total*100)/Players[Player_num].num_robots_total; else stats->kill_ratio = 0; if (Players[Player_num].hostages_total > 0 ) stats->hostage_ratio = (Players[Player_num].hostages_rescued_total*100)/Players[Player_num].hostages_total; else stats->hostage_ratio = 0; stats->seconds = f2i(Players[Player_num].time_total)+(Players[Player_num].hours_total*3600); stats->diff_level = Difficulty_level; stats->starting_level = Players[Player_num].starting_level; } static inline const char *get_placement_slot_string(const unsigned position) { switch(position) { default: Int3(); case 0: return TXT_1ST; case 1: return TXT_2ND; case 2: return TXT_3RD; case 3: return TXT_4TH; case 4: return TXT_5TH; case 5: return TXT_6TH; case 6: return TXT_7TH; case 7: return TXT_8TH; case 8: return TXT_9TH; case 9: return TXT_10TH; } } void scores_maybe_add_player(int abort_flag) { char text1[COOL_MESSAGE_LEN+10]; newmenu_item m[10]; int i,position; all_scores scores; stats_info last_game; if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) return; scores_read(&scores); position = MAX_HIGH_SCORES; for (i=0; i scores.stats[i].score ) { position = i; break; } } if ( position == MAX_HIGH_SCORES ) { if (abort_flag) return; scores_fill_struct( &last_game ); } else { if ( position==0 ) { strcpy( text1, "" ); m[0].type = NM_TYPE_TEXT; m[0].text = TXT_COOL_SAYING; m[1].type = NM_TYPE_INPUT; m[1].text = text1; m[1].text_len = COOL_MESSAGE_LEN-5; newmenu_do( TXT_HIGH_SCORE, TXT_YOU_PLACED_1ST, 2, m, NULL, NULL ); strncpy( scores.cool_saying, text1, COOL_MESSAGE_LEN ); if (strlen(scores.cool_saying)<1) sprintf( scores.cool_saying, "No Comment" ); } else { nm_messagebox( TXT_HIGH_SCORE, 1, TXT_OK, "%s %s!", TXT_YOU_PLACED, get_placement_slot_string(position)); } // move everyone down... for ( i=MAX_HIGH_SCORES-1; i>position; i-- ) { scores.stats[i] = scores.stats[i-1]; } scores_fill_struct( &scores.stats[position] ); scores_write(&scores); } scores_view(&last_game, position); if (Game_wind) window_close(Game_wind); // prevent the next game from doing funny things } void scores_rprintf(int x, int y, char * format, ... ) { va_list args; char buffer[128]; int w, h, aw; char *p; va_start(args, format ); vsprintf(buffer,format,args); va_end(args); //replace the digit '1' with special wider 1 for (p=buffer;*p;p++) if (*p=='1') *p=132; gr_get_string_size(buffer, &w, &h, &aw ); gr_string( FSPACX(x)-w, FSPACY(y), buffer ); } void scores_draw_item( int i, stats_info * stats ) { char buffer[20]; int y; y = 77+i*9; if (i==0) y -= 8; if ( i==MAX_HIGH_SCORES ) y += 8; else scores_rprintf( 57, y-3, "%d.", i+1 ); y -= 3; if (strlen(stats->name)==0) { gr_string( FSPACX(66), FSPACY(y), TXT_EMPTY ); return; } gr_printf( FSPACX(66), FSPACY(y), "%s", stats->name ); int_to_string(stats->score, buffer); scores_rprintf( 149, y, "%s", buffer ); gr_printf( FSPACX(166), FSPACY(y), "%s", MENU_DIFFICULTY_TEXT(stats->diff_level) ); if ( (stats->starting_level > 0 ) && (stats->ending_level > 0 )) scores_rprintf( 232, y, "%d-%d", stats->starting_level, stats->ending_level ); else if ( (stats->starting_level < 0 ) && (stats->ending_level > 0 )) scores_rprintf( 232, y, "S%d-%d", -stats->starting_level, stats->ending_level ); else if ( (stats->starting_level < 0 ) && (stats->ending_level < 0 )) scores_rprintf( 232, y, "S%d-S%d", -stats->starting_level, -stats->ending_level ); else if ( (stats->starting_level > 0 ) && (stats->ending_level < 0 )) scores_rprintf( 232, y, "%d-S%d", stats->starting_level, -stats->ending_level ); { int h, m, s; h = stats->seconds/3600; s = stats->seconds%3600; m = s / 60; s = s % 60; scores_rprintf( 276, y, "%d:%02d:%02d", h, m, s ); } } typedef struct scores_menu { int citem; fix64 t1; int looper; all_scores scores; stats_info last_game; } scores_menu; int scores_handler(window *wind, d_event *event, scores_menu *menu) { int i; int k; sbyte fades[64] = { 1,1,1,2,2,3,4,4,5,6,8,9,10,12,13,15,16,17,19,20,22,23,24,26,27,28,28,29,30,30,31,31,31,31,31,30,30,29,28,28,27,26,24,23,22,20,19,17,16,15,13,12,10,9,8,6,5,4,4,3,2,2,1,1 }; int w = FSPACX(290), h = FSPACY(170); switch (event->type) { case EVENT_WINDOW_ACTIVATED: game_flush_inputs(); break; case EVENT_KEY_COMMAND: k = event_key_get(event); switch( k ) { case KEY_CTRLED+KEY_R: if ( menu->citem < 0 ) { // Reset scores... if ( nm_messagebox( NULL, 2, TXT_NO, TXT_YES, TXT_RESET_HIGH_SCORES )==1 ) { PHYSFS_delete(SCORES_FILENAME); scores_view(&menu->last_game, menu->citem); // create new scores window window_close(wind); // then remove the old one } } return 1; case KEY_ENTER: case KEY_SPACEBAR: case KEY_ESC: window_close(wind); return 1; } break; case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: if (event_mouse_get_button(event) == MBTN_LEFT || event_mouse_get_button(event) == MBTN_RIGHT) { window_close(wind); return 1; } break; case EVENT_IDLE: timer_delay2(50); break; case EVENT_WINDOW_DRAW: gr_set_current_canvas(NULL); nm_draw_background(((SWIDTH-w)/2)-BORDERX,((SHEIGHT-h)/2)-BORDERY,((SWIDTH-w)/2)+w+BORDERX,((SHEIGHT-h)/2)+h+BORDERY); gr_set_current_canvas(window_get_canvas(wind)); grd_curcanv->cv_font = MEDIUM3_FONT; gr_string( 0x8000, FSPACY(15), TXT_HIGH_SCORES ); grd_curcanv->cv_font = GAME_FONT; gr_set_fontcolor( BM_XRGB(31,26,5), -1 ); gr_string( FSPACX( 71), FSPACY(50), TXT_NAME ); gr_string( FSPACX(122), FSPACY(50), TXT_SCORE ); gr_string( FSPACX(167), FSPACY(50), TXT_SKILL ); gr_string( FSPACX(210), FSPACY(50), TXT_LEVELS ); gr_string( FSPACX(253), FSPACY(50), TXT_TIME ); if ( menu->citem < 0 ) gr_string( 0x8000, FSPACY(175), TXT_PRESS_CTRL_R ); gr_set_fontcolor( BM_XRGB(28,28,28), -1 ); gr_printf( 0x8000, FSPACY(31), "%c%s%c - %s", 34, menu->scores.cool_saying, 34, menu->scores.stats[0].name ); for (i=0; iscores.stats[i] ); } if ( menu->citem > -1 ) { gr_set_fontcolor( BM_XRGB(7+fades[menu->looper],7+fades[menu->looper],7+fades[menu->looper]), -1 ); if (timer_query() >= menu->t1+F1_0/128) { menu->t1 = timer_query(); menu->looper++; if (menu->looper>63) menu->looper=0; } if ( menu->citem == MAX_HIGH_SCORES ) scores_draw_item( MAX_HIGH_SCORES, &menu->last_game ); else scores_draw_item( menu->citem, &menu->scores.stats[menu->citem] ); } gr_set_current_canvas(NULL); break; case EVENT_WINDOW_CLOSE: d_free(menu); break; default: break; } return 0; } void scores_view(stats_info *last_game, int citem) { scores_menu *menu; MALLOC(menu, scores_menu, 1); if (!menu) return; menu->citem = citem; menu->t1 = timer_query(); menu->looper = 0; if (last_game) menu->last_game = *last_game; newmenu_free_background(); scores_read(&menu->scores); set_screen_mode(SCREEN_MENU); show_menus(); window_create(&grd_curscreen->sc_canvas, (SWIDTH - FSPACX(320))/2, (SHEIGHT - FSPACY(200))/2, FSPACX(320), FSPACY(200), (int (*)(window *, d_event *, void *))scores_handler, menu); } dxx-rebirth-0.58.1-d1x/main/scores.h000066400000000000000000000064111217717257200171470ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/scores.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:42:40 $ * * Scores header. * * $Log: scores.h,v $ * Revision 1.1.1.1 2006/03/17 19:42:40 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:13:05 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:31:53 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.13 1994/12/07 00:36:36 mike * scores sequencing stuff. * * Revision 1.12 1994/11/28 11:26:09 matt * Took out scores for weapons, which are no longer used * * Revision 1.11 1994/10/24 18:20:03 john * Made the current high score flash. * * Revision 1.10 1994/10/18 18:21:36 john * NEw score system. * * Revision 1.9 1994/10/03 23:01:58 matt * New parms for scores_view() * * * Revision 1.8 1994/09/27 16:10:37 adam * changed scores of course * * Revision 1.7 1994/08/31 19:25:46 mike * Add score values for new powerups. * * Revision 1.6 1994/08/26 16:00:18 mike * enhanced (?) scoring. * * Revision 1.5 1994/08/26 13:01:45 john * Put high score system in. * * Revision 1.4 1994/05/30 16:33:21 yuan * Revamping high scores. * * Revision 1.3 1994/05/14 17:15:07 matt * Got rid of externs in source (non-header) files * * Revision 1.2 1994/05/13 13:13:57 yuan * Added player death... * * When you die, if just pops up a a message. * When game is over, a message is popped up, and if you have a high score, * you get to enter it. * * Revision 1.1 1994/05/13 10:22:16 yuan * Initial revision * * */ #ifndef _SCORES_H #define _SCORES_H #define ROBOT_SCORE 1000 #define HOSTAGE_SCORE 1000 #define CONTROL_CEN_SCORE 5000 #define ENERGY_SCORE 0 #define SHIELD_SCORE 0 #define LASER_SCORE 0 #define DEBRIS_SCORE 0 #define CLUTTER_SCORE 0 #define MISSILE1_SCORE 0 #define MISSILE4_SCORE 0 #define KEY_SCORE 0 #define QUAD_FIRE_SCORE 0 #define VULCAN_AMMO_SCORE 0 #define CLOAK_SCORE 0 #define TURBO_SCORE 0 #define INVULNERABILITY_SCORE 0 #define HEADLIGHT_SCORE 0 struct stats_info; extern void scores_view(struct stats_info *last_game, int citem); // If player has a high score, adds you to file and returns. // If abort_flag set, only show if player has gotten a high score. extern void scores_maybe_add_player(int abort_flag); #endif dxx-rebirth-0.58.1-d1x/main/screens.h000066400000000000000000000076241217717257200173220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/screens.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:44:20 $ * * Info on canvases, screens, etc. * * $Log: screens.h,v $ * Revision 1.1.1.1 2006/03/17 19:44:20 zicodxx * initial import * * Revision 1.4 1999/11/21 13:00:08 donut * Changed screen_mode format. Now directly encodes res into a 32bit int, rather than using arbitrary values. * * Revision 1.3 1999/11/20 10:05:18 donut * variable size menu patch from Jan Bobrowski. Variable menu font size support and a bunch of fixes for menus that didn't work quite right, by me (MPM). * * Revision 1.2 1999/08/14 15:49:51 donut * moved MENU_SCREEN_MODE to main/screens.h so that it can be used for the startup screen mode in inferno.c * * Revision 1.1.1.1 1999/06/14 22:13:05 donut * Import of d1x 1.37 source. * * Revision 2.2 1995/03/14 12:14:00 john * Made VR helmets have 4 resolutions to choose from. * * Revision 2.1 1995/03/06 15:24:09 john * New screen techniques. * * Revision 2.0 1995/02/27 11:31:40 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.15 1994/08/10 19:56:45 john * Changed font stuff; Took out old menu; messed up lots of * other stuff like game sequencing messages, etc. * * Revision 1.14 1994/07/20 21:04:26 john * Add VictorMax VR helment support. * * Revision 1.13 1994/06/24 17:01:28 john * Add VFX support; Took Game Sequencing, like EndGame and stuff and * took it out of game.c and into gameseq.c * * Revision 1.12 1994/04/20 20:30:03 john * *** empty log message *** * * Revision 1.11 1994/03/30 21:12:05 yuan * Use only 119 lines (saves 3 scanlines) * * Revision 1.10 1994/03/17 16:49:37 john * *** empty log message *** * * Revision 1.9 1994/02/11 15:07:44 matt * Added extern of Canv_game_offscrn * * Revision 1.8 1994/01/31 16:52:43 john * redid cockpit bounds. * * Revision 1.7 1994/01/26 18:13:53 john * Changed 3d constants.. * * Revision 1.6 1994/01/25 17:11:46 john * *** empty log message *** * * Revision 1.5 1994/01/25 11:43:25 john * Changed game window size. * * Revision 1.4 1993/12/13 16:32:39 yuan * Fixed menu system memory errors, and other bugs. * * Revision 1.3 1993/12/10 16:07:23 yuan * Working on menu system. Updated the title screen. * * Revision 1.2 1993/12/09 21:27:46 matt * Added 3d window sizing constants * * Revision 1.1 1993/12/06 09:50:33 matt * Initial revision * * * */ #ifndef _SCREEN_H #define _SCREEN_H #include "gr.h" // What graphics modes the game & editor open // for Screen_mode variable #define SCREEN_MENU 0 // viewing the menu screen #define SCREEN_GAME 1 // viewing the menu screen #define SCREEN_EDITOR 2 // viewing the editor screen extern grs_canvas Screen_3d_window; // The rectangle for rendering the mine to //from editor.c extern grs_canvas *Canv_editor; // the full on-scrren editor canvas extern grs_canvas *Canv_editor_game; // the game window on the editor screen //from game.c extern int set_screen_mode(int sm); // True = editor screen #endif dxx-rebirth-0.58.1-d1x/main/segment.h000066400000000000000000000161331217717257200173150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Include file for functions which need to access segment data structure. * */ #ifndef _SEGMENT_H #define _SEGMENT_H #include "physfsx.h" #include "pstypes.h" #include "fix.h" #include "vecmat.h" // Version 1 - Initial version // Version 2 - Mike changed some shorts to bytes in segments, so incompatible! #define SIDE_IS_QUAD 1 // render side as quadrilateral #define SIDE_IS_TRI_02 2 // render side as two triangles, triangulated along edge from 0 to 2 #define SIDE_IS_TRI_13 3 // render side as two triangles, triangulated along edge from 1 to 3 // Set maximum values for segment and face data structures. #define MAX_VERTICES_PER_SEGMENT 8 #define MAX_SIDES_PER_SEGMENT 6 #define MAX_VERTICES_PER_POLY 4 #define WLEFT 0 #define WTOP 1 #define WRIGHT 2 #define WBOTTOM 3 #define WBACK 4 #define WFRONT 5 #define MAX_SEGMENTS_ORIGINAL 900 #define MAX_SEGMENT_VERTICES_ORIGINAL (4*MAX_SEGMENTS_ORIGINAL) #define MAX_SEGMENTS 9000 #define MAX_SEGMENT_VERTICES (4*MAX_SEGMENTS) //normal everyday vertices #define DEFAULT_LIGHTING 0 // (F1_0/2) #ifdef EDITOR //verts for the new segment # define NUM_NEW_SEG_VERTICES 8 # define NEW_SEGMENT_VERTICES (MAX_SEGMENT_VERTICES) # define MAX_VERTICES (MAX_SEGMENT_VERTICES+NUM_NEW_SEG_VERTICES) #else //No editor # define MAX_VERTICES (MAX_SEGMENT_VERTICES) #endif // Returns true if segnum references a child, else returns false. // Note that -1 means no connection, -2 means a connection to the outside world. #define IS_CHILD(segnum) (segnum > -1) //Structure for storing u,v,light values. //NOTE: this structure should be the same as the one in 3d.h typedef struct uvl { fix u, v, l; } uvl; #ifdef COMPACT_SEGS typedef struct side { sbyte type; // replaces num_faces and tri_edge, 1 = quad, 2 = 0:2 triangulation, 3 = 1:3 triangulation ubyte pad; //keep us longword alligned short wall_num; short tmap_num; short tmap_num2; uvl uvls[4]; //vms_vector normals[2]; // 2 normals, if quadrilateral, both the same. } side; #else typedef struct side { sbyte type; // replaces num_faces and tri_edge, 1 = quad, 2 = 0:2 triangulation, 3 = 1:3 triangulation ubyte pad; //keep us longword alligned short wall_num; short tmap_num; short tmap_num2; uvl uvls[4]; vms_vector normals[2]; // 2 normals, if quadrilateral, both the same. } side; #endif struct segment { #ifdef EDITOR short segnum; // segment number, not sure what it means short group; // group number to which the segment belongs. #endif short objects; // pointer to objects in this segment short value; short children[MAX_SIDES_PER_SEGMENT]; // indices of 6 children segments, front, left, top, right, bottom, back side sides[MAX_SIDES_PER_SEGMENT]; // 6 sides int verts[MAX_VERTICES_PER_SEGMENT]; // vertex ids of 4 front and 4 back vertices ubyte special; // what type of center this is sbyte matcen_num; // which center segment is associated with. fix static_light; //average static light in segment int degenerated; // true if this segment has gotten turned inside out, or something. }; typedef struct segment segment; //values for special field #define SEGMENT_IS_NOTHING 0 #define SEGMENT_IS_FUELCEN 1 #define SEGMENT_IS_REPAIRCEN 2 #define SEGMENT_IS_CONTROLCEN 3 #define SEGMENT_IS_ROBOTMAKER 4 #define MAX_CENTER_TYPES 5 #ifdef COMPACT_SEGS extern void get_side_normal(segment *sp, int sidenum, int normal_num, vms_vector * vm ); extern void get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector *vm2 ); #endif // Local segment data. // This is stuff specific to a segment that does not need to get // written to disk. This is a handy separation because we can add to // this structure without obsoleting existing data on disk. #define SS_REPAIR_CENTER 0x01 // Bitmask for this segment being part of repair center. //--repair-- typedef struct { //--repair-- int special_type; //--repair-- short special_segment; // if special_type indicates repair center, this is the base of the repair center //--repair-- } lsegment; typedef struct { int num_segments; int num_vertices; short segments[MAX_SEGMENTS]; int vertices[MAX_VERTICES]; } group; // Globals from mglobal.c extern vms_vector Vertices[]; extern segment Segments[]; //--repair-- extern lsegment Lsegments[]; extern int Num_segments; extern int Num_vertices; extern sbyte Side_to_verts[MAX_SIDES_PER_SEGMENT][4]; // Side_to_verts[my_side] is list of vertices forming side my_side. extern int Side_to_verts_int[MAX_SIDES_PER_SEGMENT][4]; // Side_to_verts[my_side] is list of vertices forming side my_side. extern char Side_opposite[]; // Side_opposite[my_side] returns side opposite cube from my_side. #define SEG_PTR_2_NUM(segptr) (Assert((unsigned) (segptr-Segments) #include "inferno.h" #include "game.h" #include "vecmat.h" #include "key.h" #include "joy.h" #include "object.h" #include "dxxerror.h" #include "physics.h" #include "kconfig.h" #ifdef EDITOR #include "editor/editor.h" #endif //variables for slew system object *slew_obj=NULL; //what object is slewing, or NULL if none #define JOY_NULL 15 #define ROT_SPEED 2 //rate of rotation while key held down #define SLIDE_SPEED (700) #define ZOOM_SPEED_FACTOR (1000) //(1500) short old_joy_x,old_joy_y; //position last time around // Function Prototypes int slew_stop(void); // ------------------------------------------------------------------- //say start slewing with this object void slew_init(object *obj) { slew_obj = obj; slew_obj->control_type = CT_SLEW; slew_obj->movement_type = MT_NONE; slew_stop(); //make sure not moving } int slew_stop() { if (!slew_obj || slew_obj->control_type!=CT_SLEW) return 0; vm_vec_zero(&slew_obj->mtype.phys_info.velocity); return 1; } void slew_reset_orient() { if (!slew_obj || slew_obj->control_type!=CT_SLEW) return; slew_obj->orient.rvec.x = slew_obj->orient.uvec.y = slew_obj->orient.fvec.z = f1_0; slew_obj->orient.rvec.y = slew_obj->orient.rvec.z = slew_obj->orient.uvec.x = slew_obj->orient.uvec.z = slew_obj->orient.fvec.x = slew_obj->orient.fvec.y = 0; } int do_slew_movement(object *obj, int check_keys ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; vms_angvec rotang; if (!slew_obj || slew_obj->control_type!=CT_SLEW) return 0; if (check_keys) { #if 0 //def EDITOR // might be useful for people with playing keys set to modifiers or such, if (EditorWindow) // or just use a separate player file for the editor { obj->mtype.phys_info.velocity.x += SLIDE_SPEED * keyd_pressed[KEY_PAD9] * FrameTime; obj->mtype.phys_info.velocity.x -= SLIDE_SPEED * keyd_pressed[KEY_PAD7] * FrameTime; obj->mtype.phys_info.velocity.y += SLIDE_SPEED * keyd_pressed[KEY_PADMINUS] * FrameTime; obj->mtype.phys_info.velocity.y -= SLIDE_SPEED * keyd_pressed[KEY_PADPLUS] * FrameTime; obj->mtype.phys_info.velocity.z += ZOOM_SPEED_FACTOR * keyd_pressed[KEY_PAD8] * FrameTime; obj->mtype.phys_info.velocity.z -= ZOOM_SPEED_FACTOR * keyd_pressed[KEY_PAD2] * FrameTime; rotang.p = rotang.b = rotang.h = 0; rotang.p += keyd_pressed[KEY_LBRACKET] * FrameTime / ROT_SPEED; rotang.p -= keyd_pressed[KEY_RBRACKET] * FrameTime / ROT_SPEED; rotang.b += keyd_pressed[KEY_PAD1] * FrameTime / ROT_SPEED; rotang.b -= keyd_pressed[KEY_PAD3] * FrameTime / ROT_SPEED; rotang.h += keyd_pressed[KEY_PAD6] * FrameTime / ROT_SPEED; rotang.h -= keyd_pressed[KEY_PAD4] * FrameTime / ROT_SPEED; } else #endif { obj->mtype.phys_info.velocity.x = SLIDE_SPEED * Controls.sideways_thrust_time; obj->mtype.phys_info.velocity.y = SLIDE_SPEED * Controls.vertical_thrust_time; obj->mtype.phys_info.velocity.z = ZOOM_SPEED_FACTOR * Controls.forward_thrust_time; rotang.p = Controls.pitch_time/ROT_SPEED ; rotang.b = Controls.bank_time/ROT_SPEED; rotang.h = Controls.heading_time/ROT_SPEED; } } else rotang.p = rotang.b = rotang.h = 0; moved = rotang.p | rotang.b | rotang.h; vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; vm_transpose_matrix(&new_pm); //make those columns rows moved |= obj->mtype.phys_info.velocity.x | obj->mtype.phys_info.velocity.y | obj->mtype.phys_info.velocity.z; svel = obj->mtype.phys_info.velocity; vm_vec_scale(&svel,FrameTime); //movement in this frame vm_vec_rotate(&movement,&svel,&new_pm); // obj->last_pos = obj->pos; vm_vec_add2(&obj->pos,&movement); moved |= (movement.x || movement.y || movement.z); if (moved) update_object_seg(obj); //update segment id return moved; } //do slew for this frame int slew_frame(int check_keys) { return do_slew_movement( slew_obj, !check_keys ); } dxx-rebirth-0.58.1-d1x/main/slew.h000066400000000000000000000043541217717257200166270ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/slew.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:43:42 $ * * Prototypes, etc., for slew system * * $Log: slew.h,v $ * Revision 1.1.1.1 2006/03/17 19:43:42 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:13:08 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:33:05 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.5 1994/12/15 16:43:58 matt * Made slew functions compile out for release versions * * Revision 1.4 1994/02/17 11:32:41 matt * Changes in object system * * Revision 1.3 1994/01/05 10:53:42 john * New object code by John. * * Revision 1.2 1993/12/05 22:48:57 matt * Reworked include files in an attempt to cut down on build times * * Revision 1.1 1993/12/05 20:20:16 matt * Initial revision * * */ #ifndef _SLEW_H #define _SLEW_H #include "object.h" //from slew.c #if 1 //ndef RELEASE //kill error on RELEASE build void slew_init(object *obj); // say this is slew obj int slew_stop(); // Stops object void slew_reset_orient(); // Resets orientation int slew_frame(int dont_check_keys); // Does slew frame #else #define slew_init(obj) #define slew_stop(obj) #define slew_reset_orient() //#define slew_frame(dont_check_keys) //KRB hack int slew_frame(int dont_check_keys); // Does slew frame #endif #endif dxx-rebirth-0.58.1-d1x/main/snddecom.c000066400000000000000000000054321217717257200174420ustar00rootroot00000000000000//THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX //SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO //END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A //ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS //IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS //SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE //FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE //CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS //AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. //COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. // // $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/snddecom.c,v $ // $Revision: 1.1.1.1 $ // $Author: zicodxx $ // $Date: 2006/03/17 19:43:28 $ // // Routines for compressing digital sounds. // // $Log: snddecom.c,v $ // Revision 1.1.1.1 2006/03/17 19:43:28 zicodxx // initial import // // Revision 1.1.1.1 1999/06/14 22:11:34 donut // Import of d1x 1.37 source. // // Revision 2.0 1995/02/27 11:29:36 john // New version 2.0, which has no anonymous unions, builds with // Watcom 10.0, and doesn't require parsing BITMAPS.TBL. // // Revision 1.2 1994/11/30 14:08:46 john // First version. // Revision 1.1 1994/11/29 14:33:51 john // Initial revision // int index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 }; int step_table[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,1060,1166,1282,1411,1552, 1707,1878, 2066,2272,2499,2749,3024,3327,3660,4026, 4428,4871,5358,5894,6484,7132,7845,8630, 9493,10442,11487,12635,13899,15289,16818, 18500,20350,22385,24623,27086,29794,32767 }; void sound_decompress(unsigned char *data, int size, unsigned char *outp) { int newtoken = 1; int predicted = 0, index = 0, step = 7; int code, diff, out; while (size) { if (newtoken) code = (*data) & 15; else { code = (*(data++)) >> 4; size--; } newtoken ^= 1; diff = 0; if (code & 4) diff += step; if (code & 2) diff += (step >> 1); if (code & 1) diff += (step >> 2); diff += (step >> 3); if (code & 8) diff = -diff; out = predicted + diff; if (out > 32767) out = 32767; if (out < -32768) out = -32768; predicted = out; *(outp++) = ((out >> 8) & 255) ^ 0x80; index += index_table[code]; if (index < 0) index = 0; if (index > 88) index = 88; step = step_table[index]; } } dxx-rebirth-0.58.1-d1x/main/snddecom.h000066400000000000000000000001741217717257200174450ustar00rootroot00000000000000#ifndef _SNDDECOM_H #define _SNDDECOM_H void sound_decompress(unsigned char *data, int size, unsigned char *outp); #endif dxx-rebirth-0.58.1-d1x/main/songs.c000066400000000000000000000337201217717257200170000ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to manage the songs in Descent. * */ #include #include #include #include "dxxerror.h" #include "pstypes.h" #include "songs.h" #include "digi.h" #include "rbaudio.h" #ifdef USE_SDLMIXER #include "digi_mixer_music.h" #include "jukebox.h" #endif #include "config.h" #include "timer.h" #include "args.h" int Songs_initialized = 0; static int Song_playing = -1; // -1 if no song playing, else the Descent song number static int Redbook_playing = 0; // Redbook track num differs from Song_playing. We need this for Redbook repeat hooks. bim_song_info *BIMSongs = NULL; int Num_bim_songs; #define EXTMUSIC_VOLUME_SCALE (255) //takes volume in range 0..8 //NOTE that we do not check what is playing right now (except Redbook) This is because here we don't (want) know WHAT we're playing - let the subfunctions do it (i.e. digi_win32_set_music_volume() knows if a MIDI plays or not) void songs_set_volume(int volume) { #ifdef _WIN32 digi_win32_set_midi_volume(volume); #endif if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) { RBASetVolume(0); RBASetVolume(volume); } #ifdef USE_SDLMIXER mix_set_music_volume(volume); #endif } // Set up everything for our music // NOTE: you might think this is done once per runtime but it's not! It's done for EACH song so that each mission can have it's own descent.sng structure. We COULD optimize that by only doing this once per mission. void songs_init() { int i = 0; char inputline[80+1]; PHYSFS_file * fp = NULL; char sng_file[PATH_MAX]; Songs_initialized = 0; if (BIMSongs != NULL) d_free(BIMSongs); memset(sng_file, '\0', sizeof(sng_file)); if (fp == NULL) // try dxx-r.sng - a songfile specifically for dxx which level authors CAN use (dxx does not care if descent.sng contains MP3/OGG/etc. as well) besides the normal descent.sng containing files other versions of the game cannot play. this way a mission can contain a DOS-Descent compatible OST (hmp files) as well as a OST using MP3, OGG, etc. fp = PHYSFSX_openReadBuffered( "dxx-r.sng" ); if (fp == NULL) // try to open regular descent.sng fp = PHYSFSX_openReadBuffered( "descent.sng" ); if ( fp == NULL ) // No descent.sng available. Define a default song-set { int predef=30; // define 30 songs - period MALLOC(BIMSongs, bim_song_info, predef); if (!BIMSongs) return; strncpy(BIMSongs[SONG_TITLE].filename, "descent.hmp",sizeof(BIMSongs[SONG_TITLE].filename)); strncpy(BIMSongs[SONG_BRIEFING].filename, "briefing.hmp",sizeof(BIMSongs[SONG_BRIEFING].filename)); strncpy(BIMSongs[SONG_CREDITS].filename, "credits.hmp",sizeof(BIMSongs[SONG_CREDITS].filename)); strncpy(BIMSongs[SONG_ENDLEVEL].filename, "endlevel.hmp",sizeof(BIMSongs[SONG_ENDLEVEL].filename)); // can't find it? give a warning strncpy(BIMSongs[SONG_ENDGAME].filename, "endgame.hmp",sizeof(BIMSongs[SONG_ENDGAME].filename)); // ditto for (i = SONG_FIRST_LEVEL_SONG; i < predef; i++) { snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i - SONG_FIRST_LEVEL_SONG + 1); if (!PHYSFSX_exists(BIMSongs[i].filename,1)) snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%d.hmp", i - SONG_FIRST_LEVEL_SONG); if (!PHYSFSX_exists(BIMSongs[i].filename,1)) { memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename)); // music not available break; } } } else { while (!PHYSFS_eof(fp)) { PHYSFSX_fgets(inputline, sizeof(inputline), fp ); if ( strlen( inputline ) ) { BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+1)); memset(BIMSongs[i].filename, '\0', sizeof(BIMSongs[i].filename)); sscanf( inputline, "%15s", BIMSongs[i].filename ); if (strrchr(BIMSongs[i].filename, '.')) if (!d_stricmp(strrchr(BIMSongs[i].filename, '.'), SONG_EXT_HMP) #ifdef USE_SDLMIXER || !d_stricmp(strrchr(BIMSongs[i].filename, '.'), SONG_EXT_MID) || !d_stricmp(strrchr(BIMSongs[i].filename, '.'), SONG_EXT_OGG) || !d_stricmp(strrchr(BIMSongs[i].filename, '.'), SONG_EXT_FLAC) || !d_stricmp(strrchr(BIMSongs[i].filename, '.'), SONG_EXT_MP3) #endif ) i++; } } // HACK: If Descent.hog is patched from 1.0 to 1.5, descent.sng is turncated. So let's patch it up here if (i==12 && PHYSFSX_fsize("descent.sng")==422) { BIMSongs = d_realloc(BIMSongs, sizeof(bim_song_info)*(i+15)); for (i = 12; i <= 26; i++) snprintf(BIMSongs[i].filename, sizeof(BIMSongs[i].filename), "game%02d.hmp", i-4); } } Num_bim_songs = i; Songs_initialized = 1; if (fp != NULL) PHYSFS_close(fp); if (GameArg.SndNoMusic) GameCfg.MusicType = MUSIC_TYPE_NONE; // If SDL_Mixer is not supported (or deactivated), switch to no-music type if SDL_mixer-related music type was selected #ifdef USE_SDLMIXER if (GameArg.SndDisableSdlMixer) #else if (1) #endif { #ifndef _WIN32 if (GameCfg.MusicType == MUSIC_TYPE_BUILTIN) GameCfg.MusicType = MUSIC_TYPE_NONE; #endif if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM) GameCfg.MusicType = MUSIC_TYPE_NONE; } if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) RBAInit(); #ifdef USE_SDLMIXER else if (GameCfg.MusicType == MUSIC_TYPE_CUSTOM) jukebox_load(); #endif songs_set_volume(GameCfg.MusicVolume); } void songs_uninit() { songs_stop_all(); #ifdef USE_SDLMIXER jukebox_unload(); #endif if (BIMSongs != NULL) d_free(BIMSongs); Songs_initialized = 0; } //stop any songs - builtin, redbook or jukebox - that are currently playing void songs_stop_all(void) { #ifdef _WIN32 digi_win32_stop_midi_song(); // Stop midi song, if playing #endif RBAStop(); #ifdef USE_SDLMIXER mix_stop_music(); #endif Song_playing = -1; } void songs_pause(void) { #ifdef _WIN32 digi_win32_pause_midi_song(); #endif if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) RBAPause(); #ifdef USE_SDLMIXER mix_pause_music(); #endif } void songs_resume(void) { #ifdef _WIN32 digi_win32_resume_midi_song(); #endif if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) RBAResume(); #ifdef USE_SDLMIXER mix_resume_music(); #endif } void songs_pause_resume(void) { if (GameCfg.MusicType == MUSIC_TYPE_REDBOOK) RBAPauseResume(); #ifdef USE_SDLMIXER mix_pause_resume_music(); #endif } /* * This list may not be exhaustive!! */ #define D1_MAC_OEM_DISCID 0xde0feb0e // Descent CD that came with the Mac Performa 6400, hope mine isn't scratched [too much] #define REDBOOK_ENDLEVEL_TRACK 4 #define REDBOOK_ENDGAME_TRACK (RBAGetNumberOfTracks()) #define REDBOOK_FIRST_LEVEL_TRACK (songs_haved1_cd() ? 6 : 1) // songs_haved1_cd returns 1 if the descent 1 Mac CD is in the drive and // 0 otherwise int songs_haved1_cd() { int discid; if (GameCfg.OrigTrackOrder) return 1; if (!(GameCfg.MusicType == MUSIC_TYPE_REDBOOK)) return 0; discid = RBAGetDiscID(); switch (discid) { case D1_MAC_OEM_DISCID: // Doesn't work with your Mac Descent CD? Please tell! return 1; default: return 0; } } void redbook_repeat_func() { stop_time(); RBAPlayTracks(Redbook_playing, 0, redbook_repeat_func); start_time(); } // play a filename as music, depending on filename extension. int songs_play_file(char *filename, int repeat, void (*hook_finished_track)()) { char *fptr = strrchr(filename, '.'); songs_stop_all(); if (fptr == NULL) return 0; if (!d_stricmp(fptr, SONG_EXT_HMP)) { #if defined(_WIN32) return digi_win32_play_midi_song( filename, repeat ); #elif defined(USE_SDLMIXER) return mix_play_file( filename, repeat, hook_finished_track ); #else return 0; #endif } #if defined(USE_SDLMIXER) else if ( !d_stricmp(fptr, SONG_EXT_MID) || !d_stricmp(fptr, SONG_EXT_OGG) || !d_stricmp(fptr, SONG_EXT_FLAC) || !d_stricmp(fptr, SONG_EXT_MP3) ) { return mix_play_file( filename, repeat, hook_finished_track ); } #endif return 0; } int songs_play_song( int songnum, int repeat ) { songs_init(); if (!Songs_initialized) return 0; switch (GameCfg.MusicType) { case MUSIC_TYPE_BUILTIN: { // EXCEPTION: If SONG_ENDLEVEL is not available, continue playing level song. if (Song_playing >= SONG_FIRST_LEVEL_SONG && songnum == SONG_ENDLEVEL && !PHYSFSX_exists(BIMSongs[songnum].filename, 1)) return Song_playing; Song_playing = -1; if (songs_play_file(BIMSongs[songnum].filename, repeat, NULL)) Song_playing = songnum; break; } case MUSIC_TYPE_REDBOOK: { int num_tracks = RBAGetNumberOfTracks(); Song_playing = -1; if ((songnum < SONG_ENDGAME) && (songnum + 2 <= num_tracks)) { if (RBAPlayTracks(songnum + 2, songnum + 2, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = songnum + 2; Song_playing = songnum; } } else if ((songnum == SONG_ENDGAME) && (REDBOOK_ENDGAME_TRACK <= num_tracks)) // The endgame track is the last track { if (RBAPlayTracks(REDBOOK_ENDGAME_TRACK, REDBOOK_ENDGAME_TRACK, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = REDBOOK_ENDGAME_TRACK; Song_playing = songnum; } } else if ((songnum > SONG_ENDGAME) && (songnum + 1 <= num_tracks)) { if (RBAPlayTracks(songnum + 1, songnum + 1, repeat ? redbook_repeat_func : NULL)) { Redbook_playing = songnum + 1; Song_playing = songnum; } } break; } #ifdef USE_SDLMIXER case MUSIC_TYPE_CUSTOM: { // EXCEPTION: If SONG_ENDLEVEL is undefined, continue playing level song. if (Song_playing >= SONG_FIRST_LEVEL_SONG && songnum == SONG_ENDLEVEL && !strlen(GameCfg.CMMiscMusic[songnum])) return Song_playing; Song_playing = -1; if (songs_play_file(GameCfg.CMMiscMusic[songnum], repeat, NULL)) Song_playing = songnum; break; } #endif default: Song_playing = -1; break; } return Song_playing; } void redbook_first_song_func() { stop_time(); Song_playing = -1; // Playing Redbook tracks will not modify Song_playing. To repeat we must reset this so songs_play_level_song does not think we want to re-play the same song again. songs_play_level_song(1, 0); start_time(); } // play track given by levelnum (depending on the music type and it's playing behaviour) or increment/decrement current track number via offset value int songs_play_level_song( int levelnum, int offset ) { int songnum; Assert( levelnum != 0 ); songs_init(); if (!Songs_initialized) return 0; songnum = (levelnum>0)?(levelnum-1):(-levelnum); switch (GameCfg.MusicType) { case MUSIC_TYPE_BUILTIN: { if (offset) return Song_playing; Song_playing = -1; if ((Num_bim_songs - SONG_FIRST_LEVEL_SONG) > 0) { songnum = SONG_FIRST_LEVEL_SONG + (songnum % (Num_bim_songs - SONG_FIRST_LEVEL_SONG)); if (songs_play_file(BIMSongs[songnum].filename, 1, NULL)) Song_playing = songnum; } break; } case MUSIC_TYPE_REDBOOK: { int n_tracks = RBAGetNumberOfTracks(); int tracknum; if (!offset) { // we have just been told to play the same as we do already -> ignore if (Song_playing >= SONG_FIRST_LEVEL_SONG && songnum + SONG_FIRST_LEVEL_SONG == Song_playing) return Song_playing; tracknum = REDBOOK_FIRST_LEVEL_TRACK + ((n_tracks<=REDBOOK_FIRST_LEVEL_TRACK) ? 0 : (songnum % (n_tracks-REDBOOK_FIRST_LEVEL_TRACK))); } else { tracknum = Redbook_playing+offset; if (tracknum < REDBOOK_FIRST_LEVEL_TRACK) tracknum = n_tracks - (REDBOOK_FIRST_LEVEL_TRACK - tracknum) + 1; else if (tracknum > n_tracks) tracknum = REDBOOK_FIRST_LEVEL_TRACK + (tracknum - n_tracks) - 1; } Song_playing = -1; if (RBAEnabled() && (tracknum <= n_tracks)) { if (RBAPlayTracks(tracknum, !songs_haved1_cd()?n_tracks:tracknum, songs_haved1_cd() ? redbook_repeat_func : redbook_first_song_func)) { Song_playing = songnum + SONG_FIRST_LEVEL_SONG; Redbook_playing = tracknum; } } break; } #ifdef USE_SDLMIXER case MUSIC_TYPE_CUSTOM: { if (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_RAND) GameCfg.CMLevelMusicTrack[0] = d_rand() % GameCfg.CMLevelMusicTrack[1]; // simply a random selection - no check if this song has already been played. But that's how I roll! else if (!offset) { if (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_CONT) { static int last_songnum = -1; if (Song_playing >= SONG_FIRST_LEVEL_SONG) return Song_playing; // As soon as we start a new level, go to next track if (last_songnum != -1 && songnum != last_songnum) ((GameCfg.CMLevelMusicTrack[0]+1>=GameCfg.CMLevelMusicTrack[1])?GameCfg.CMLevelMusicTrack[0]=0:GameCfg.CMLevelMusicTrack[0]++); last_songnum = songnum; } else if (GameCfg.CMLevelMusicPlayOrder == MUSIC_CM_PLAYORDER_LEVEL) GameCfg.CMLevelMusicTrack[0] = (songnum % GameCfg.CMLevelMusicTrack[1]); } else { GameCfg.CMLevelMusicTrack[0] += offset; if (GameCfg.CMLevelMusicTrack[0] < 0) GameCfg.CMLevelMusicTrack[0] = GameCfg.CMLevelMusicTrack[1] + GameCfg.CMLevelMusicTrack[0]; if (GameCfg.CMLevelMusicTrack[0] + 1 > GameCfg.CMLevelMusicTrack[1]) GameCfg.CMLevelMusicTrack[0] = GameCfg.CMLevelMusicTrack[0] - GameCfg.CMLevelMusicTrack[1]; } Song_playing = -1; if (jukebox_play()) Song_playing = songnum + SONG_FIRST_LEVEL_SONG; break; } #endif default: Song_playing = -1; break; } // If we couldn't play the song, most likely because it wasn't specified, play no music. if (Song_playing == -1) songs_stop_all(); return Song_playing; } // check which song is playing, or -1 if not playing anything int songs_is_playing() { return Song_playing; } dxx-rebirth-0.58.1-d1x/main/songs.h000066400000000000000000000021641217717257200170030ustar00rootroot00000000000000/* * * Header for songs.c * */ #ifndef _SONGS_H #define _SONGS_H typedef struct bim_song_info { char filename[16]; } bim_song_info; #define SONG_TITLE 0 #define SONG_BRIEFING 1 #define SONG_ENDLEVEL 2 #define SONG_ENDGAME 3 #define SONG_CREDITS 4 #define SONG_FIRST_LEVEL_SONG 5 #define SONG_EXT_HMP ".hmp" #ifdef USE_SDLMIXER #define SONG_EXT_MID ".mid" #define SONG_EXT_OGG ".ogg" #define SONG_EXT_FLAC ".flac" #define SONG_EXT_MP3 ".mp3" #endif int songs_play_file(char *filename, int repeat, void (*hook_finished_track)()); int songs_play_song( int songnum, int repeat ); int songs_play_level_song( int levelnum, int offset ); //stop any songs - midi, redbook or jukebox - that are currently playing void songs_stop_all(void); void songs_pause(void); void songs_resume(void); void songs_pause_resume(void); // check which song is playing, or -1 if not playing anything int songs_is_playing(); // set volume for selected music playback system void songs_set_volume(int volume); void songs_uninit(); #endif dxx-rebirth-0.58.1-d1x/main/sounds.h000066400000000000000000000213531217717257200171660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/main/sounds.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:42:23 $ * * Numbering system for the sounds. * * $Log: sounds.h,v $ * Revision 1.1.1.1 2006/03/17 19:42:23 zicodxx * initial import * * Revision 1.2 2000/04/18 01:18:24 sekmu * Changed/fixed altsounds (mostly done) * * Revision 1.1.1.1 1999/06/14 22:13:10 donut * Import of d1x 1.37 source. * * Revision 2.0 1995/02/27 11:27:32 john * New version 2.0, which has no anonymous unions, builds with * Watcom 10.0, and doesn't require parsing BITMAPS.TBL. * * Revision 1.41 1995/02/03 17:08:28 john * Changed sound stuff to allow low memory usage. * Also, changed so that Sounds isn't an array of digi_sounds, it * is a ubyte pointing into GameSounds, this way the digi.c code that * locks sounds won't accidentally unlock a sound that is already playing, but * since it's Sounds[soundno] is different, it would erroneously be unlocked. * * Revision 1.40 1995/01/30 21:45:17 adam * added weapon change sounds * * Revision 1.39 1995/01/30 21:11:57 mike * Use new weapon selection sounds, different for primary and secondary. * * Revision 1.38 1995/01/26 17:02:58 mike * make fusion cannon have more chrome, make fusion, mega rock you! * * Revision 1.37 1995/01/18 19:46:15 matt * Added sound for invulnerability wearing off, and voice message for cheating * * Revision 1.36 1995/01/18 19:05:04 john * Increased MAX_SOUNDS. * * Revision 1.35 1994/12/14 16:57:08 adam * *** empty log message *** * * Revision 1.34 1994/12/08 21:31:40 adam * *** empty log message *** * * Revision 1.33 1994/12/08 12:33:01 mike * make boss dying more interesting. * * Revision 1.32 1994/12/04 21:39:40 matt * Added sound constants for endlevel explosions * * Revision 1.31 1994/11/30 14:02:58 mike * see/claw/attack sounds. * * Revision 1.30 1994/11/29 20:43:54 matt * Deleted a bunch of unused constants * * Revision 1.29 1994/11/29 15:48:11 matt * Cleaned up, & added new sounds * * Revision 1.28 1994/11/29 14:35:36 adam * moved lava noise index * * Revision 1.27 1994/11/29 13:23:30 matt * Cleaned up sound constants * * Revision 1.26 1994/11/29 13:01:04 rob * ADded badass explosion define. * * Revision 1.25 1994/11/29 11:34:23 rob * Added new HUD sounds. * * Revision 1.24 1994/11/15 16:52:01 mike * hiss sound placeholder. * * Revision 1.23 1994/10/25 16:21:45 adam * changed homing sound * * Revision 1.22 1994/10/23 00:27:34 matt * Made exploding wall do one long sound, instead of lots of small ones * * Revision 1.21 1994/10/22 14:12:35 mike * Add sound for missile tracking player. * * Revision 1.20 1994/10/11 12:25:21 matt * Added "hot rocks" that create badass explosion when hit by weapons * * Revision 1.19 1994/10/10 20:57:50 matt * Added sound for exploding wall (hostage door) * * Revision 1.18 1994/10/04 15:33:31 john * Took out the old PLAY_SOUND??? code and replaced it * with direct calls into digi_link_??? so that all sounds * can be made 3d. * * Revision 1.17 1994/09/29 21:13:41 john * Added Master volumes for digi and midi. Also took out panning, * because it doesn't work with MasterVolume stuff. * * Revision 1.16 1994/09/29 00:42:29 matt * Made hitting a locked door play a sound * * Revision 1.15 1994/09/20 19:14:34 john * Massaged the sound system; used a better formula for determining * which l/r balance, also, put in Mike's stuff that searches for a connection * between the 2 sounds' segments, stopping for closed doors, etc. * * Revision 1.14 1994/07/06 15:23:59 john * Revamped hostage sound. * * Revision 1.13 1994/06/21 19:13:27 john * *** empty log message *** * * Revision 1.12 1994/06/21 12:09:54 adam * *** empty log message *** * * Revision 1.11 1994/06/21 12:03:15 john * Added more sounds. * * Revision 1.10 1994/06/20 22:01:54 matt * Added prototype for Play3D() * * Revision 1.9 1994/06/20 21:06:06 yuan * Fixed up menus. * * Revision 1.8 1994/06/17 12:21:54 mike * Hook for robot hits player. * * Revision 1.7 1994/06/15 19:01:35 john * Added the capability to make 3d sounds play just once for the * laser hit wall effects. * * Revision 1.6 1994/06/08 11:43:03 john * Enable 3D sound. * * Revision 1.5 1994/06/07 18:21:20 john * Start changing sound to the new 3D system. * * Revision 1.4 1994/05/16 16:17:41 john * Bunch of stuff on my Inferno Task list May16-23 * * Revision 1.3 1994/05/09 21:11:38 john * Sound changes; pass index instead of pointer to digi routines. * Made laser sound cut off the last laser sound. * * Revision 1.2 1994/04/27 11:47:46 john * First version. * * Revision 1.1 1994/04/26 10:44:36 john * Initial revision * * */ #ifndef _SOUNDS_H #define _SOUNDS_H #include "vecmat.h" #include "digi.h" //------------------- List of sound effects -------------------- #define SOUND_LASER_FIRED 10 #define SOUND_WEAPON_HIT_DOOR 27 #define SOUND_WEAPON_HIT_BLASTABLE 11 #define SOUND_BADASS_EXPLOSION 11 // need something different for this if possible #define SOUND_ROBOT_HIT_PLAYER 17 #define SOUND_ROBOT_HIT 20 #define SOUND_ROBOT_DESTROYED 21 #define SOUND_VOLATILE_WALL_HIT 21 #define SOUND_LASER_HIT_CLUTTER 30 #define SOUND_CONTROL_CENTER_HIT 30 #define SOUND_EXPLODING_WALL 31 // one long sound #define SOUND_CONTROL_CENTER_DESTROYED 31 #define SOUND_CONTROL_CENTER_WARNING_SIREN 32 #define SOUND_MINE_BLEW_UP 33 #define SOUND_FUSION_WARMUP 34 #define SOUND_REFUEL_STATION_GIVING_FUEL 62 #define SOUND_PLAYER_HIT_WALL 70 #define SOUND_PLAYER_GOT_HIT 71 #define SOUND_HOSTAGE_RESCUED 91 #define SOUND_COUNTDOWN_0_SECS 100 // countdown 100..114 #define SOUND_COUNTDOWN_13_SECS 113 #define SOUND_COUNTDOWN_29_SECS 114 #define SOUND_HUD_MESSAGE 117 #define SOUND_HUD_KILL 118 #define SOUND_HOMING_WARNING 122 // Warning beep: You are being tracked by a missile! Borrowed from old repair center sounds. #define SOUND_VOLATILE_WALL_HISS 151 // need a hiss sound here. #define SOUND_GOOD_SELECTION_PRIMARY (PCSharePig?155:153) #define SOUND_BAD_SELECTION 156 #define SOUND_GOOD_SELECTION_SECONDARY (PCSharePig?155:154) // Adam: New sound number here! MK, 01/30/95 #define SOUND_ALREADY_SELECTED 155 // Adam: New sound number here! MK, 01/30/95 #define SOUND_CHEATER (PCSharePig?156:200) // moved by Victor Rachels #define SOUND_CLOAK_OFF 161 // sound when cloak goes away #define SOUND_INVULNERABILITY_OFF 163 // sound when invulnerability goes away #define SOUND_BOSS_SHARE_SEE 183 #define SOUND_BOSS_SHARE_ATTACK 184 #define SOUND_BOSS_SHARE_DIE 185 #define SOUND_NASTY_ROBOT_HIT_1 190 // ding.raw ; tearing metal 1 #define SOUND_NASTY_ROBOT_HIT_2 191 // ding.raw ; tearing metal 2 #define ROBOT_SEE_SOUND_DEFAULT 170 #define ROBOT_ATTACK_SOUND_DEFAULT 171 #define ROBOT_CLAW_SOUND_DEFAULT 190 #define SOUND_BIG_ENDLEVEL_EXPLOSION SOUND_EXPLODING_WALL #define SOUND_TUNNEL_EXPLOSION SOUND_EXPLODING_WALL #define SOUND_DROP_BOMB 26 //-------------------------------------------------------------- #define MAX_SOUNDS 250 // I think it would be nice to have a scrape sound... //#define SOUND_PLAYER_SCRAPE_WALL 72 extern ubyte Sounds[MAX_SOUNDS]; extern digi_sound GameSounds[MAX_SOUNDS]; extern ubyte AltSounds[MAX_SOUNDS]; #endif dxx-rebirth-0.58.1-d1x/main/state.c000066400000000000000000001525161217717257200167740ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to save/restore game state. * */ #include #include #include #include #include "pstypes.h" #include "inferno.h" #include "segment.h" #include "textures.h" #include "wall.h" #include "object.h" #include "gamemine.h" #include "dxxerror.h" #include "gamefont.h" #include "gameseg.h" #include "switch.h" #include "game.h" #include "newmenu.h" #include "fuelcen.h" #include "hash.h" #include "key.h" #include "piggy.h" #include "player.h" #include "cntrlcen.h" #include "morph.h" #include "weapon.h" #include "render.h" #include "gameseq.h" #include "gauges.h" #include "newdemo.h" #include "automap.h" #include "piggy.h" #include "paging.h" #include "titles.h" #include "text.h" #include "mission.h" #include "pcx.h" #include "u_mem.h" #include "args.h" #include "ai.h" #include "state.h" #include "multi.h" #include "gr.h" #ifdef OGL #include "ogl_init.h" #endif #include "physfsx.h" #define STATE_VERSION 7 #define STATE_COMPATIBLE_VERSION 6 // 0 - Put DGSS (Descent Game State Save) id at tof. // 1 - Added Difficulty level save // 2 - Added cheats.enabled flag // 3 - Added between levels save. // 4 - Added mission support // 5 - Mike changed ai and object structure. // 6 - Added buggin' cheat save // 7 - Added other cheat saves and game_id. #define NUM_SAVES 10 #define THUMBNAIL_W 100 #define THUMBNAIL_H 50 #define DESC_LENGTH 20 extern int Do_appearance_effect; int state_save_all_sub(char *filename, char *desc); int state_restore_all_sub(char *filename); int sc_last_item= 0; char dgss_id[4] = "DGSS"; uint state_game_id; // Following functions convert object to object_rw and back to be written to/read from Savegames. Mostly object differs to object_rw in terms of timer values (fix/fix64). as we reset GameTime64 for writing so it can fit into fix it's not necessary to increment savegame version. But if we once store something else into object which might be useful after restoring, it might be handy to increment Savegame version and actually store these new infos. // turn object to object_rw to be saved to Savegame. void state_object_to_object_rw(object *obj, object_rw *obj_rw) { obj_rw->signature = obj->signature; obj_rw->type = obj->type; obj_rw->id = obj->id; obj_rw->next = obj->next; obj_rw->prev = obj->prev; obj_rw->control_type = obj->control_type; obj_rw->movement_type = obj->movement_type; obj_rw->render_type = obj->render_type; obj_rw->flags = obj->flags; obj_rw->segnum = obj->segnum; obj_rw->attached_obj = obj->attached_obj; obj_rw->pos.x = obj->pos.x; obj_rw->pos.y = obj->pos.y; obj_rw->pos.z = obj->pos.z; obj_rw->orient.rvec.x = obj->orient.rvec.x; obj_rw->orient.rvec.y = obj->orient.rvec.y; obj_rw->orient.rvec.z = obj->orient.rvec.z; obj_rw->orient.fvec.x = obj->orient.fvec.x; obj_rw->orient.fvec.y = obj->orient.fvec.y; obj_rw->orient.fvec.z = obj->orient.fvec.z; obj_rw->orient.uvec.x = obj->orient.uvec.x; obj_rw->orient.uvec.y = obj->orient.uvec.y; obj_rw->orient.uvec.z = obj->orient.uvec.z; obj_rw->size = obj->size; obj_rw->shields = obj->shields; obj_rw->last_pos.x = obj->last_pos.x; obj_rw->last_pos.y = obj->last_pos.y; obj_rw->last_pos.z = obj->last_pos.z; obj_rw->contains_type = obj->contains_type; obj_rw->contains_id = obj->contains_id; obj_rw->contains_count= obj->contains_count; obj_rw->matcen_creator= obj->matcen_creator; obj_rw->lifeleft = obj->lifeleft; switch (obj_rw->movement_type) { case MT_PHYSICS: obj_rw->mtype.phys_info.velocity.x = obj->mtype.phys_info.velocity.x; obj_rw->mtype.phys_info.velocity.y = obj->mtype.phys_info.velocity.y; obj_rw->mtype.phys_info.velocity.z = obj->mtype.phys_info.velocity.z; obj_rw->mtype.phys_info.thrust.x = obj->mtype.phys_info.thrust.x; obj_rw->mtype.phys_info.thrust.y = obj->mtype.phys_info.thrust.y; obj_rw->mtype.phys_info.thrust.z = obj->mtype.phys_info.thrust.z; obj_rw->mtype.phys_info.mass = obj->mtype.phys_info.mass; obj_rw->mtype.phys_info.drag = obj->mtype.phys_info.drag; obj_rw->mtype.phys_info.brakes = obj->mtype.phys_info.brakes; obj_rw->mtype.phys_info.rotvel.x = obj->mtype.phys_info.rotvel.x; obj_rw->mtype.phys_info.rotvel.y = obj->mtype.phys_info.rotvel.y; obj_rw->mtype.phys_info.rotvel.z = obj->mtype.phys_info.rotvel.z; obj_rw->mtype.phys_info.rotthrust.x = obj->mtype.phys_info.rotthrust.x; obj_rw->mtype.phys_info.rotthrust.y = obj->mtype.phys_info.rotthrust.y; obj_rw->mtype.phys_info.rotthrust.z = obj->mtype.phys_info.rotthrust.z; obj_rw->mtype.phys_info.turnroll = obj->mtype.phys_info.turnroll; obj_rw->mtype.phys_info.flags = obj->mtype.phys_info.flags; break; case MT_SPINNING: obj_rw->mtype.spin_rate.x = obj->mtype.spin_rate.x; obj_rw->mtype.spin_rate.y = obj->mtype.spin_rate.y; obj_rw->mtype.spin_rate.z = obj->mtype.spin_rate.z; break; } switch (obj_rw->control_type) { case CT_WEAPON: obj_rw->ctype.laser_info.parent_type = obj->ctype.laser_info.parent_type; obj_rw->ctype.laser_info.parent_num = obj->ctype.laser_info.parent_num; obj_rw->ctype.laser_info.parent_signature = obj->ctype.laser_info.parent_signature; if (obj->ctype.laser_info.creation_time - GameTime64 < F1_0*(-18000)) obj_rw->ctype.laser_info.creation_time = F1_0*(-18000); else obj_rw->ctype.laser_info.creation_time = obj->ctype.laser_info.creation_time - GameTime64; obj_rw->ctype.laser_info.last_hitobj = obj->ctype.laser_info.last_hitobj; obj_rw->ctype.laser_info.track_goal = obj->ctype.laser_info.track_goal; obj_rw->ctype.laser_info.multiplier = obj->ctype.laser_info.multiplier; break; case CT_EXPLOSION: obj_rw->ctype.expl_info.spawn_time = obj->ctype.expl_info.spawn_time; obj_rw->ctype.expl_info.delete_time = obj->ctype.expl_info.delete_time; obj_rw->ctype.expl_info.delete_objnum = obj->ctype.expl_info.delete_objnum; obj_rw->ctype.expl_info.attach_parent = obj->ctype.expl_info.attach_parent; obj_rw->ctype.expl_info.prev_attach = obj->ctype.expl_info.prev_attach; obj_rw->ctype.expl_info.next_attach = obj->ctype.expl_info.next_attach; break; case CT_AI: { int i; obj_rw->ctype.ai_info.behavior = obj->ctype.ai_info.behavior; for (i = 0; i < MAX_AI_FLAGS; i++) obj_rw->ctype.ai_info.flags[i] = obj->ctype.ai_info.flags[i]; obj_rw->ctype.ai_info.hide_segment = obj->ctype.ai_info.hide_segment; obj_rw->ctype.ai_info.hide_index = obj->ctype.ai_info.hide_index; obj_rw->ctype.ai_info.path_length = obj->ctype.ai_info.path_length; obj_rw->ctype.ai_info.cur_path_index = obj->ctype.ai_info.cur_path_index; obj_rw->ctype.ai_info.follow_path_start_seg = obj->ctype.ai_info.follow_path_start_seg; obj_rw->ctype.ai_info.follow_path_end_seg = obj->ctype.ai_info.follow_path_end_seg; obj_rw->ctype.ai_info.danger_laser_signature = obj->ctype.ai_info.danger_laser_signature; obj_rw->ctype.ai_info.danger_laser_num = obj->ctype.ai_info.danger_laser_num; break; } case CT_LIGHT: obj_rw->ctype.light_info.intensity = obj->ctype.light_info.intensity; break; case CT_POWERUP: obj_rw->ctype.powerup_info.count = obj->ctype.powerup_info.count; break; } switch (obj_rw->render_type) { case RT_MORPH: case RT_POLYOBJ: case RT_NONE: // HACK below { int i; if (obj->render_type == RT_NONE && obj->type != OBJ_GHOST) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. Here it's not important, but it might be for Multiplayer Savegames. break; obj_rw->rtype.pobj_info.model_num = obj->rtype.pobj_info.model_num; for (i=0;irtype.pobj_info.anim_angles[i].p = obj->rtype.pobj_info.anim_angles[i].p; obj_rw->rtype.pobj_info.anim_angles[i].b = obj->rtype.pobj_info.anim_angles[i].b; obj_rw->rtype.pobj_info.anim_angles[i].h = obj->rtype.pobj_info.anim_angles[i].h; } obj_rw->rtype.pobj_info.subobj_flags = obj->rtype.pobj_info.subobj_flags; obj_rw->rtype.pobj_info.tmap_override = obj->rtype.pobj_info.tmap_override; obj_rw->rtype.pobj_info.alt_textures = obj->rtype.pobj_info.alt_textures; break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj_rw->rtype.vclip_info.vclip_num = obj->rtype.vclip_info.vclip_num; obj_rw->rtype.vclip_info.frametime = obj->rtype.vclip_info.frametime; obj_rw->rtype.vclip_info.framenum = obj->rtype.vclip_info.framenum; break; case RT_LASER: break; } } // turn object_rw to object after reading from Savegame void state_object_rw_to_object(object_rw *obj_rw, object *obj) { obj->signature = obj_rw->signature; obj->type = obj_rw->type; obj->id = obj_rw->id; obj->next = obj_rw->next; obj->prev = obj_rw->prev; obj->control_type = obj_rw->control_type; obj->movement_type = obj_rw->movement_type; obj->render_type = obj_rw->render_type; obj->flags = obj_rw->flags; obj->segnum = obj_rw->segnum; obj->attached_obj = obj_rw->attached_obj; obj->pos.x = obj_rw->pos.x; obj->pos.y = obj_rw->pos.y; obj->pos.z = obj_rw->pos.z; obj->orient.rvec.x = obj_rw->orient.rvec.x; obj->orient.rvec.y = obj_rw->orient.rvec.y; obj->orient.rvec.z = obj_rw->orient.rvec.z; obj->orient.fvec.x = obj_rw->orient.fvec.x; obj->orient.fvec.y = obj_rw->orient.fvec.y; obj->orient.fvec.z = obj_rw->orient.fvec.z; obj->orient.uvec.x = obj_rw->orient.uvec.x; obj->orient.uvec.y = obj_rw->orient.uvec.y; obj->orient.uvec.z = obj_rw->orient.uvec.z; obj->size = obj_rw->size; obj->shields = obj_rw->shields; obj->last_pos.x = obj_rw->last_pos.x; obj->last_pos.y = obj_rw->last_pos.y; obj->last_pos.z = obj_rw->last_pos.z; obj->contains_type = obj_rw->contains_type; obj->contains_id = obj_rw->contains_id; obj->contains_count= obj_rw->contains_count; obj->matcen_creator= obj_rw->matcen_creator; obj->lifeleft = obj_rw->lifeleft; switch (obj->movement_type) { case MT_PHYSICS: obj->mtype.phys_info.velocity.x = obj_rw->mtype.phys_info.velocity.x; obj->mtype.phys_info.velocity.y = obj_rw->mtype.phys_info.velocity.y; obj->mtype.phys_info.velocity.z = obj_rw->mtype.phys_info.velocity.z; obj->mtype.phys_info.thrust.x = obj_rw->mtype.phys_info.thrust.x; obj->mtype.phys_info.thrust.y = obj_rw->mtype.phys_info.thrust.y; obj->mtype.phys_info.thrust.z = obj_rw->mtype.phys_info.thrust.z; obj->mtype.phys_info.mass = obj_rw->mtype.phys_info.mass; obj->mtype.phys_info.drag = obj_rw->mtype.phys_info.drag; obj->mtype.phys_info.brakes = obj_rw->mtype.phys_info.brakes; obj->mtype.phys_info.rotvel.x = obj_rw->mtype.phys_info.rotvel.x; obj->mtype.phys_info.rotvel.y = obj_rw->mtype.phys_info.rotvel.y; obj->mtype.phys_info.rotvel.z = obj_rw->mtype.phys_info.rotvel.z; obj->mtype.phys_info.rotthrust.x = obj_rw->mtype.phys_info.rotthrust.x; obj->mtype.phys_info.rotthrust.y = obj_rw->mtype.phys_info.rotthrust.y; obj->mtype.phys_info.rotthrust.z = obj_rw->mtype.phys_info.rotthrust.z; obj->mtype.phys_info.turnroll = obj_rw->mtype.phys_info.turnroll; obj->mtype.phys_info.flags = obj_rw->mtype.phys_info.flags; break; case MT_SPINNING: obj->mtype.spin_rate.x = obj_rw->mtype.spin_rate.x; obj->mtype.spin_rate.y = obj_rw->mtype.spin_rate.y; obj->mtype.spin_rate.z = obj_rw->mtype.spin_rate.z; break; } switch (obj->control_type) { case CT_WEAPON: obj->ctype.laser_info.parent_type = obj_rw->ctype.laser_info.parent_type; obj->ctype.laser_info.parent_num = obj_rw->ctype.laser_info.parent_num; obj->ctype.laser_info.parent_signature = obj_rw->ctype.laser_info.parent_signature; obj->ctype.laser_info.creation_time = obj_rw->ctype.laser_info.creation_time; obj->ctype.laser_info.last_hitobj = obj_rw->ctype.laser_info.last_hitobj; obj->ctype.laser_info.hitobj_list[obj->ctype.laser_info.last_hitobj] = 1; // restore most recent hitobj to hitobj_list obj->ctype.laser_info.track_goal = obj_rw->ctype.laser_info.track_goal; obj->ctype.laser_info.multiplier = obj_rw->ctype.laser_info.multiplier; break; case CT_EXPLOSION: obj->ctype.expl_info.spawn_time = obj_rw->ctype.expl_info.spawn_time; obj->ctype.expl_info.delete_time = obj_rw->ctype.expl_info.delete_time; obj->ctype.expl_info.delete_objnum = obj_rw->ctype.expl_info.delete_objnum; obj->ctype.expl_info.attach_parent = obj_rw->ctype.expl_info.attach_parent; obj->ctype.expl_info.prev_attach = obj_rw->ctype.expl_info.prev_attach; obj->ctype.expl_info.next_attach = obj_rw->ctype.expl_info.next_attach; break; case CT_AI: { int i; obj->ctype.ai_info.behavior = obj_rw->ctype.ai_info.behavior; for (i = 0; i < MAX_AI_FLAGS; i++) obj->ctype.ai_info.flags[i] = obj_rw->ctype.ai_info.flags[i]; obj->ctype.ai_info.hide_segment = obj_rw->ctype.ai_info.hide_segment; obj->ctype.ai_info.hide_index = obj_rw->ctype.ai_info.hide_index; obj->ctype.ai_info.path_length = obj_rw->ctype.ai_info.path_length; obj->ctype.ai_info.cur_path_index = obj_rw->ctype.ai_info.cur_path_index; obj->ctype.ai_info.follow_path_start_seg = obj_rw->ctype.ai_info.follow_path_start_seg; obj->ctype.ai_info.follow_path_end_seg = obj_rw->ctype.ai_info.follow_path_end_seg; obj->ctype.ai_info.danger_laser_signature = obj_rw->ctype.ai_info.danger_laser_signature; obj->ctype.ai_info.danger_laser_num = obj_rw->ctype.ai_info.danger_laser_num; break; } case CT_LIGHT: obj->ctype.light_info.intensity = obj_rw->ctype.light_info.intensity; break; case CT_POWERUP: obj->ctype.powerup_info.count = obj_rw->ctype.powerup_info.count; break; case CT_CNTRLCEN: { // gun points of reactor now part of the object but of course not saved in object_rw and overwritten due to reset_objects(). Let's just recompute them. int i = 0; reactor *reactor = get_reactor_definition(obj->id); for (i=0; in_guns; i++) calc_controlcen_gun_point(reactor, obj, i); break; } } switch (obj->render_type) { case RT_MORPH: case RT_POLYOBJ: case RT_NONE: // HACK below { int i; if (obj->render_type == RT_NONE && obj->type != OBJ_GHOST) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. Here it's not important, but it might be for Multiplayer Savegames. break; obj->rtype.pobj_info.model_num = obj_rw->rtype.pobj_info.model_num; for (i=0;irtype.pobj_info.anim_angles[i].p = obj_rw->rtype.pobj_info.anim_angles[i].p; obj->rtype.pobj_info.anim_angles[i].b = obj_rw->rtype.pobj_info.anim_angles[i].b; obj->rtype.pobj_info.anim_angles[i].h = obj_rw->rtype.pobj_info.anim_angles[i].h; } obj->rtype.pobj_info.subobj_flags = obj_rw->rtype.pobj_info.subobj_flags; obj->rtype.pobj_info.tmap_override = obj_rw->rtype.pobj_info.tmap_override; obj->rtype.pobj_info.alt_textures = obj_rw->rtype.pobj_info.alt_textures; break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: obj->rtype.vclip_info.vclip_num = obj_rw->rtype.vclip_info.vclip_num; obj->rtype.vclip_info.frametime = obj_rw->rtype.vclip_info.frametime; obj->rtype.vclip_info.framenum = obj_rw->rtype.vclip_info.framenum; break; case RT_LASER: break; } } // Following functions convert player to player_rw and back to be written to/read from Savegames. player only differ to player_rw in terms of timer values (fix/fix64). as we reset GameTime64 for writing so it can fit into fix it's not necessary to increment savegame version. But if we once store something else into object which might be useful after restoring, it might be handy to increment Savegame version and actually store these new infos. // turn player to player_rw to be saved to Savegame. void state_player_to_player_rw(player *pl, player_rw *pl_rw) { int i=0; memcpy(pl_rw->callsign, pl->callsign, CALLSIGN_LEN+1); memcpy(pl_rw->net_address, pl->net_address, 6); pl_rw->connected = pl->connected; pl_rw->objnum = pl->objnum; pl_rw->n_packets_got = pl->n_packets_got; pl_rw->n_packets_sent = pl->n_packets_sent; pl_rw->flags = pl->flags; pl_rw->energy = pl->energy; pl_rw->shields = pl->shields; pl_rw->lives = pl->lives; pl_rw->level = pl->level; pl_rw->laser_level = pl->laser_level; pl_rw->starting_level = pl->starting_level; pl_rw->killer_objnum = pl->killer_objnum; pl_rw->primary_weapon_flags = pl->primary_weapon_flags; pl_rw->secondary_weapon_flags = pl->secondary_weapon_flags; for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) pl_rw->primary_ammo[i] = pl->primary_ammo[i]; for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) pl_rw->secondary_ammo[i] = pl->secondary_ammo[i]; pl_rw->last_score = pl->last_score; pl_rw->score = pl->score; pl_rw->time_level = pl->time_level; pl_rw->time_total = pl->time_total; if (pl->cloak_time - GameTime64 < F1_0*(-18000)) pl_rw->cloak_time = F1_0*(-18000); else pl_rw->cloak_time = pl->cloak_time - GameTime64; if (pl->invulnerable_time - GameTime64 < F1_0*(-18000)) pl_rw->invulnerable_time = F1_0*(-18000); else pl_rw->invulnerable_time = pl->invulnerable_time - GameTime64; pl_rw->net_killed_total = pl->net_killed_total; pl_rw->net_kills_total = pl->net_kills_total; pl_rw->num_kills_level = pl->num_kills_level; pl_rw->num_kills_total = pl->num_kills_total; pl_rw->num_robots_level = pl->num_robots_level; pl_rw->num_robots_total = pl->num_robots_total; pl_rw->hostages_rescued_total = pl->hostages_rescued_total; pl_rw->hostages_total = pl->hostages_total; pl_rw->hostages_on_board = pl->hostages_on_board; pl_rw->hostages_level = pl->hostages_level; pl_rw->homing_object_dist = pl->homing_object_dist; pl_rw->hours_level = pl->hours_level; pl_rw->hours_total = pl->hours_total; } // turn player_rw to player after reading from Savegame void state_player_rw_to_player(player_rw *pl_rw, player *pl) { int i=0; memcpy(pl->callsign, pl_rw->callsign, CALLSIGN_LEN+1); memcpy(pl->net_address, pl_rw->net_address, 6); pl->connected = pl_rw->connected; pl->objnum = pl_rw->objnum; pl->n_packets_got = pl_rw->n_packets_got; pl->n_packets_sent = pl_rw->n_packets_sent; pl->flags = pl_rw->flags; pl->energy = pl_rw->energy; pl->shields = pl_rw->shields; pl->lives = pl_rw->lives; pl->level = pl_rw->level; pl->laser_level = pl_rw->laser_level; pl->starting_level = pl_rw->starting_level; pl->killer_objnum = pl_rw->killer_objnum; pl->primary_weapon_flags = pl_rw->primary_weapon_flags; pl->secondary_weapon_flags = pl_rw->secondary_weapon_flags; for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) pl->primary_ammo[i] = pl_rw->primary_ammo[i]; for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) pl->secondary_ammo[i] = pl_rw->secondary_ammo[i]; pl->last_score = pl_rw->last_score; pl->score = pl_rw->score; pl->time_level = pl_rw->time_level; pl->time_total = pl_rw->time_total; pl->cloak_time = pl_rw->cloak_time; pl->invulnerable_time = pl_rw->invulnerable_time; pl->net_killed_total = pl_rw->net_killed_total; pl->net_kills_total = pl_rw->net_kills_total; pl->num_kills_level = pl_rw->num_kills_level; pl->num_kills_total = pl_rw->num_kills_total; pl->num_robots_level = pl_rw->num_robots_level; pl->num_robots_total = pl_rw->num_robots_total; pl->hostages_rescued_total = pl_rw->hostages_rescued_total; pl->hostages_total = pl_rw->hostages_total; pl->hostages_on_board = pl_rw->hostages_on_board; pl->hostages_level = pl_rw->hostages_level; pl->homing_object_dist = pl_rw->homing_object_dist; pl->hours_level = pl_rw->hours_level; pl->hours_total = pl_rw->hours_total; } //------------------------------------------------------------------- int state_callback(newmenu *menu, d_event *event, grs_bitmap *sc_bmp[]) { newmenu_item *items = newmenu_get_items(menu); int citem = newmenu_get_citem(menu); if ( (citem > 0) && (event->type == EVENT_NEWMENU_DRAW) ) { if ( sc_bmp[citem-1] ) { grs_canvas *save_canv = grd_curcanv; #ifndef OGL grs_canvas *temp_canv = gr_create_canvas(FSPACX(THUMBNAIL_W),FSPACY(THUMBNAIL_H)); #else grs_canvas *temp_canv = gr_create_canvas(THUMBNAIL_W*2,(THUMBNAIL_H*24/10)); #endif grs_point vertbuf[3] = {{0,0}, {0,0}, {i2f(THUMBNAIL_W*2),i2f(THUMBNAIL_H*24/10)} }; gr_set_current_canvas(temp_canv); scale_bitmap(sc_bmp[citem-1], vertbuf, 0); gr_set_current_canvas( save_canv ); #ifndef OGL gr_bitmap( (grd_curcanv->cv_bitmap.bm_w/2)-FSPACX(THUMBNAIL_W/2),items[0].y-3, &temp_canv->cv_bitmap); #else ogl_ubitmapm_cs((grd_curcanv->cv_bitmap.bm_w/2)-FSPACX(THUMBNAIL_W/2),items[0].y-FSPACY(3),FSPACX(THUMBNAIL_W),FSPACY(THUMBNAIL_H),&temp_canv->cv_bitmap,-1,F1_0); #endif gr_free_canvas(temp_canv); } return 1; } return 0; } #if 0 void rpad_string( char * string, int max_chars ) { int i, end_found; end_found = 0; for( i=0; i= STATE_COMPATIBLE_VERSION) || (SWAPINT(version) >= STATE_COMPATIBLE_VERSION)) { // Read description PHYSFS_read(fp, desc[i], sizeof(char) * DESC_LENGTH, 1); //rpad_string( desc[i], DESC_LENGTH-1 ); if (dsc == NULL) m[i+1].type = NM_TYPE_MENU; // Read thumbnail sc_bmp[i] = gr_create_bitmap(THUMBNAIL_W,THUMBNAIL_H ); PHYSFS_read(fp, sc_bmp[i]->bm_data, THUMBNAIL_W * THUMBNAIL_H, 1); nsaves++; valid = 1; } } PHYSFS_close(fp); } if (!valid) { strcpy( desc[i], TXT_EMPTY ); //rpad_string( desc[i], DESC_LENGTH-1 ); if (dsc == NULL) m[i+1].type = NM_TYPE_TEXT; } if (dsc != NULL) { m[i+1].type = NM_TYPE_INPUT_MENU; } m[i+1].text_len = DESC_LENGTH-1; m[i+1].text = desc[i]; } if ( dsc == NULL && nsaves < 1 ) { nm_messagebox( NULL, 1, "Ok", "No saved games were found!" ); return 0; } sc_last_item = -1; if (blind_save && state_quick_item < 0) blind_save = 0; // haven't picked a slot yet if (blind_save) choice = state_default_item + 1; else choice = newmenu_do2( NULL, caption, NUM_SAVES+1, m, (int (*)(newmenu *, d_event *, void *))state_callback, sc_bmp, state_default_item + 1, NULL ); for (i=0; i 0) { strcpy( fname, filename[choice-1] ); if ( dsc != NULL ) strcpy( dsc, desc[choice-1] ); state_quick_item = state_default_item = choice - 1; return choice; } return 0; } int state_get_save_file(char * fname, char * dsc, int blind_save) { return state_get_savegame_filename(fname, dsc, "Save Game", blind_save); } int state_get_restore_file(char * fname) { return state_get_savegame_filename(fname, NULL, "Select Game to Restore", 0); } int state_save_old_game(int slotnum, char * sg_name, player_rw * sg_player, int sg_difficulty_level, int sg_primary_weapon, int sg_secondary_weapon, int sg_next_level_num ) { int i; int temp_int; ubyte temp_byte; char desc[DESC_LENGTH+1]; char filename[PATH_MAX]; char mission_filename[9]; grs_canvas * cnv; PHYSFS_file * fp; #ifdef OGL int j; GLint gl_draw_buffer; #endif snprintf( filename, PATH_MAX, (GameArg.SysUsePlayersDir?"Players/%s.sg%d":"%s.sg%d"), sg_player->callsign, slotnum ); fp = PHYSFSX_openWriteBuffered(filename); if ( !fp ) return 0; //Save id PHYSFS_write(fp, dgss_id, sizeof(char) * 4, 1); //Save version temp_int = STATE_VERSION; PHYSFS_write(fp, &temp_int, sizeof(int), 1); //Save description strncpy( desc, sg_name, DESC_LENGTH ); PHYSFS_write(fp, desc, sizeof(char) * DESC_LENGTH, 1); // Save the current screen shot... cnv = gr_create_canvas( THUMBNAIL_W, THUMBNAIL_H ); if ( cnv ) { #ifdef OGL ubyte *buf; int k; #endif grs_canvas * cnv_save; cnv_save = grd_curcanv; gr_set_current_canvas( cnv ); render_frame(0); #ifdef OGL buf = d_malloc(THUMBNAIL_W * THUMBNAIL_H * 4); #ifndef OGLES glGetIntegerv(GL_DRAW_BUFFER, &gl_draw_buffer); glReadBuffer(gl_draw_buffer); #endif glReadPixels(0, SHEIGHT - THUMBNAIL_H, THUMBNAIL_W, THUMBNAIL_H, GL_RGBA, GL_UNSIGNED_BYTE, buf); k = THUMBNAIL_H; for (i = 0; i < THUMBNAIL_W * THUMBNAIL_H; i++) { if (!(j = i % THUMBNAIL_W)) k--; cnv->cv_bitmap.bm_data[THUMBNAIL_W * k + j] = gr_find_closest_color(buf[4*i]/4, buf[4*i+1]/4, buf[4*i+2]/4); } d_free(buf); #endif PHYSFS_write(fp, cnv->cv_bitmap.bm_data, THUMBNAIL_W * THUMBNAIL_H, 1); gr_set_current_canvas(cnv_save); gr_free_canvas( cnv ); } else { ubyte color = 0; for ( i=0; ilevel; PHYSFS_write(fp, &temp_int, sizeof(int), 1); temp_int = sg_next_level_num; PHYSFS_write(fp, &temp_int, sizeof(int), 1); //Save GameTime temp_int = 0; PHYSFS_write(fp, &temp_int, sizeof(fix), 1); //Save player info PHYSFS_write(fp, &sg_player, sizeof(player_rw), 1); // Save the current weapon info temp_byte = sg_primary_weapon; PHYSFS_write(fp, &temp_byte, sizeof(sbyte), 1); temp_byte = sg_secondary_weapon; PHYSFS_write(fp, &temp_byte, sizeof(sbyte), 1); // Save the difficulty level temp_int = sg_difficulty_level; PHYSFS_write(fp, &temp_int, sizeof(int), 1); // Save the cheats.enabled temp_int = 0; PHYSFS_write(fp, &cheats.enabled, sizeof(int), 1); PHYSFS_write( fp, &cheats.turbo, sizeof(int), 1); PHYSFS_write( fp, &state_game_id, sizeof(uint), 1 ); PHYSFS_write( fp, &cheats.rapidfire, sizeof(int), 1 ); PHYSFS_write( fp, &temp_int, sizeof(int), 1 ); // was Ugly_robot_cheat PHYSFS_write( fp, &temp_int, sizeof(int), 1 ); // Ugly_robot_texture PHYSFS_write( fp, &cheats.ghostphysics, sizeof(int), 1 ); PHYSFS_write( fp, &temp_int, sizeof(int), 1 ); // was Lunacy PHYSFS_close(fp); return 1; } // ----------------------------------------------------------------------------------- int state_save_all(int blind_save) { int rval; char filename[PATH_MAX], desc[DESC_LENGTH+1]; if ( Game_mode & GM_MULTI ) { if (Game_mode & GM_MULTI_COOP) multi_initiate_save_game(); return 0; } stop_time(); memset(&filename, '\0', PATH_MAX); memset(&desc, '\0', DESC_LENGTH+1); if (!state_get_save_file(filename, desc, blind_save)) { start_time(); return 0; } rval = state_save_all_sub(filename, desc); if (rval) HUD_init_message_literal(HM_DEFAULT, "Game saved"); return rval; } int state_save_all_sub(char *filename, char *desc) { int i,j; PHYSFS_file *fp; grs_canvas * cnv; char mission_filename[9]; #ifdef OGL GLint gl_draw_buffer; #endif fix tmptime32 = 0; #ifndef NDEBUG if (GameArg.SysUsePlayersDir && strncmp(filename, "Players/", 8)) Int3(); #endif fp = PHYSFSX_openWriteBuffered(filename); if ( !fp ) { nm_messagebox(NULL, 1, TXT_OK, "Error writing savegame.\nPossibly out of disk\nspace."); start_time(); return 0; } //Save id PHYSFS_write(fp, dgss_id, sizeof(char) * 4, 1); //Save version i = STATE_VERSION; PHYSFS_write(fp, &i, sizeof(int), 1); // Save Coop state_game_id and this Player's callsign. Oh the redundancy... we have this one later on but Coop games want to read this before loading a state so for easy access save this here, too if (Game_mode & GM_MULTI_COOP) { PHYSFS_write(fp, &state_game_id, sizeof(uint), 1); PHYSFS_write(fp, &Players[Player_num].callsign, sizeof(char)*CALLSIGN_LEN+1, 1); } //Save description PHYSFS_write(fp, desc, sizeof(char) * DESC_LENGTH, 1); // Save the current screen shot... cnv = gr_create_canvas( THUMBNAIL_W, THUMBNAIL_H ); if ( cnv ) { #ifdef OGL ubyte *buf; int k; #endif grs_canvas * cnv_save; cnv_save = grd_curcanv; gr_set_current_canvas( cnv ); render_frame(0); #if defined(OGL) buf = d_malloc(THUMBNAIL_W * THUMBNAIL_H * 4); #ifndef OGLES glGetIntegerv(GL_DRAW_BUFFER, &gl_draw_buffer); glReadBuffer(gl_draw_buffer); #endif glReadPixels(0, SHEIGHT - THUMBNAIL_H, THUMBNAIL_W, THUMBNAIL_H, GL_RGBA, GL_UNSIGNED_BYTE, buf); k = THUMBNAIL_H; for (i = 0; i < THUMBNAIL_W * THUMBNAIL_H; i++) { if (!(j = i % THUMBNAIL_W)) k--; cnv->cv_bitmap.bm_data[THUMBNAIL_W * k + j] = gr_find_closest_color(buf[4*i]/4, buf[4*i+1]/4, buf[4*i+2]/4); } d_free(buf); #endif PHYSFS_write(fp, cnv->cv_bitmap.bm_data, THUMBNAIL_W * THUMBNAIL_H, 1); gr_set_current_canvas(cnv_save); gr_free_canvas( cnv ); } else { ubyte color = 0; for ( i=0; iobj->control_type = md->morph_save_control_type; md->obj->movement_type = md->morph_save_movement_type; md->obj->render_type = RT_POLYOBJ; md->obj->mtype.phys_info = md->morph_save_phys_info; md->obj = NULL; } else { //maybe loaded half-morphed from disk Objects[i].flags |= OF_SHOULD_BE_DEAD; Objects[i].render_type = RT_POLYOBJ; Objects[i].control_type = CT_NONE; Objects[i].movement_type = MT_NONE; } } } //Save object info i = Highest_object_index+1; PHYSFS_write(fp, &i, sizeof(int), 1); //PHYSFS_write(fp, Objects, sizeof(object), i); for (i = 0; i <= Highest_object_index; i++) { object_rw *obj_rw; MALLOC(obj_rw, object_rw, 1); memset(obj_rw, 0, sizeof(object_rw)); state_object_to_object_rw(&Objects[i], obj_rw); PHYSFS_write(fp, obj_rw, sizeof(object_rw), 1); d_free(obj_rw); } //Save wall info i = Num_walls; PHYSFS_write(fp, &i, sizeof(int), 1); PHYSFS_write(fp, Walls, sizeof(wall), i); //Save door info i = Num_open_doors; PHYSFS_write(fp, &i, sizeof(int), 1); PHYSFS_write(fp, ActiveDoors, sizeof(active_door), i); //Save trigger info PHYSFS_write(fp, &Num_triggers, sizeof(int), 1); PHYSFS_write(fp, Triggers, sizeof(trigger), Num_triggers); //Save tmap info for (i = 0; i <= Highest_segment_index; i++) { for (j = 0; j < 6; j++) { PHYSFS_write(fp, &Segments[i].sides[j].wall_num, sizeof(short), 1); PHYSFS_write(fp, &Segments[i].sides[j].tmap_num, sizeof(short), 1); PHYSFS_write(fp, &Segments[i].sides[j].tmap_num2, sizeof(short), 1); } } // Save the fuelcen info PHYSFS_write(fp, &Control_center_destroyed, sizeof(int), 1); PHYSFS_write(fp, &Countdown_seconds_left, sizeof(int), 1); PHYSFS_write(fp, &Num_robot_centers, sizeof(int), 1); PHYSFS_write(fp, RobotCenters, sizeof(matcen_info), Num_robot_centers); PHYSFS_write(fp, &ControlCenterTriggers, sizeof(control_center_triggers), 1); PHYSFS_write(fp, &Num_fuelcenters, sizeof(int), 1); for (i = 0; i < Num_fuelcenters; i++) { // NOTE: Usually Descent1 handles countdown by Timer value of the Reactor Station. Since we now use Descent2 code to handle countdown (which we do in case there IS NO Reactor Station which causes potential trouble in Multiplayer), let's find the Reactor here and store the timer in it. if (Station[i].Type == SEGMENT_IS_CONTROLCEN) Station[i].Timer = Countdown_timer; PHYSFS_write(fp, &Station[i], sizeof(FuelCenter), 1); } // PHYSFS_write(fp, Station, sizeof(FuelCenter), Num_fuelcenters); // Save the control cen info PHYSFS_write(fp, &Control_center_been_hit, sizeof(int), 1); PHYSFS_write(fp, &Control_center_player_been_seen, sizeof(int), 1); PHYSFS_write(fp, &Control_center_next_fire_time, sizeof(int), 1); PHYSFS_write(fp, &Control_center_present, sizeof(int), 1); PHYSFS_write(fp, &Dead_controlcen_object_num, sizeof(int), 1); // Save the AI state ai_save_state( fp ); // Save the automap visited info if ( Highest_segment_index+1 > MAX_SEGMENTS_ORIGINAL ) { PHYSFS_write(fp, Automap_visited, sizeof(ubyte), Highest_segment_index + 1); } else PHYSFS_write(fp, Automap_visited, sizeof(ubyte), MAX_SEGMENTS_ORIGINAL); PHYSFS_write(fp, &state_game_id, sizeof(uint), 1); i = 0; PHYSFS_write(fp, &cheats.rapidfire, sizeof(int), 1); PHYSFS_write(fp, &i, sizeof(int), 1); // was Ugly_robot_cheat PHYSFS_write(fp, &i, sizeof(int), 1); // was Ugly_robot_texture PHYSFS_write(fp, &cheats.ghostphysics, sizeof(int), 1); PHYSFS_write(fp, &i, sizeof(int), 1); // was Lunacy // Save Coop Info if (Game_mode & GM_MULTI_COOP) { for (i = 0; i < MAX_PLAYERS; i++) // I know, I know we only allow 4 players in coop. I screwed that up. But if we ever allow 8 players in coop, who's gonna laugh then? { player_rw *pl_rw; MALLOC(pl_rw, player_rw, 1); memset(pl_rw, 0, sizeof(player_rw)); state_player_to_player_rw(&Players[i], pl_rw); PHYSFS_write(fp, pl_rw, sizeof(player_rw), 1); d_free(pl_rw); } PHYSFS_write(fp, &Netgame.mission_title, sizeof(char), MISSION_NAME_LEN+1); PHYSFS_write(fp, &Netgame.mission_name, sizeof(char), 9); PHYSFS_write(fp, &Netgame.levelnum, sizeof(int), 1); PHYSFS_write(fp, &Netgame.difficulty, sizeof(ubyte), 1); PHYSFS_write(fp, &Netgame.game_status, sizeof(ubyte), 1); PHYSFS_write(fp, &Netgame.numplayers, sizeof(ubyte), 1); PHYSFS_write(fp, &Netgame.max_numplayers, sizeof(ubyte), 1); PHYSFS_write(fp, &Netgame.numconnected, sizeof(ubyte), 1); PHYSFS_write(fp, &Netgame.level_time, sizeof(int), 1); } PHYSFS_close(fp); start_time(); return 1; } // ----------------------------------------------------------------------------------- int state_restore_all(int in_game) { char filename[PATH_MAX]; if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_stop_recording(); if ( Newdemo_state != ND_STATE_NORMAL ) return 0; if ( Game_mode & GM_MULTI ) { if (Game_mode & GM_MULTI_COOP) multi_initiate_restore_game(); return 0; } stop_time(); if (!state_get_restore_file(filename)) { start_time(); return 0; } if ( in_game ) { int choice; choice = nm_messagebox( NULL, 2, "Yes", "No", "Restore Game?" ); if ( choice != 0 ) { start_time(); return 0; } } start_time(); return state_restore_all_sub(filename); } int state_restore_all_sub(char *filename) { int ObjectStartLocation; int BogusSaturnShit = 0; int version,i, j, segnum, coop_player_got[MAX_PLAYERS], coop_org_objnum = Players[Player_num].objnum; object * obj; PHYSFS_file *fp; int swap = 0; // if file is not endian native, have to swap all shorts and ints int current_level; char mission[16]; char desc[DESC_LENGTH+1]; char id[5]; char org_callsign[CALLSIGN_LEN+16]; fix tmptime32 = 0; player_rw *pl_rw; #ifndef NDEBUG if (GameArg.SysUsePlayersDir && strncmp(filename, "Players/", 8)) Int3(); #endif fp = PHYSFSX_openReadBuffered(filename); if ( !fp ) return 0; //Read id PHYSFS_read(fp, id, sizeof(char) * 4, 1); if ( memcmp( id, dgss_id, 4 )) { PHYSFS_close(fp); return 0; } //Read version //Check for swapped file here, as dgss_id is written as a string (i.e. endian independent) PHYSFS_read(fp, &version, sizeof(int), 1); if (version & 0xffff0000) { swap = 1; version = SWAPINT(version); } if (version < STATE_COMPATIBLE_VERSION) { PHYSFS_close(fp); return 0; } // Read Coop state_game_id. Oh the redundancy... we have this one later on but Coop games want to read this before loading a state so for easy access we have this here if (Game_mode & GM_MULTI_COOP) { char saved_callsign[CALLSIGN_LEN+1]; state_game_id = PHYSFSX_readSXE32(fp, swap); PHYSFS_read(fp, &saved_callsign, sizeof(char)*CALLSIGN_LEN+1, 1); if (strcmp(saved_callsign, Players[Player_num].callsign)) // check the callsign of the player who saved this state. It MUST match. If we transferred this savegame from pilot A to pilot B, others won't be able to restore us. So bail out here if this is the case. { PHYSFS_close(fp); return 0; } } // Read description PHYSFS_read(fp, desc, sizeof(char) * DESC_LENGTH, 1); // Skip the current screen shot... PHYSFS_seek(fp, PHYSFS_tell(fp) + THUMBNAIL_W * THUMBNAIL_H); // Read the Between levels flag... i = PHYSFSX_readSXE32(fp, swap); i = 0; // Read the mission info... PHYSFS_read(fp, mission, sizeof(char) * 9, 1); if (!load_mission_by_name( mission )) { nm_messagebox( NULL, 1, "Ok", "Error!\nUnable to load mission\n'%s'\n", mission ); PHYSFS_close(fp); return 0; } //Read level info current_level = PHYSFSX_readSXE32(fp, swap); PHYSFS_seek(fp, PHYSFS_tell(fp) + sizeof(PHYSFS_sint32)); // skip Next_level_num //Restore GameTime tmptime32 = PHYSFSX_readSXE32(fp, swap); GameTime64 = (fix64)tmptime32; // Start new game.... if (!(Game_mode & GM_MULTI_COOP)) { Game_mode = GM_NORMAL; #ifdef NETWORK change_playernum_to(0); #endif N_players = 1; strcpy( org_callsign, Players[0].callsign ); InitPlayerObject(); //make sure player's object set up init_player_stats_game(0); //clear all stats } else // in coop we want to stay the player we are already. { strcpy( org_callsign, Players[Player_num].callsign ); init_player_stats_game(Player_num); } if (Game_wind) window_set_visible(Game_wind, 0); //Read player info StartNewLevelSub(current_level, 1, 0);//use page_in_textures here to fix OGL texture precashing crash -MPM MALLOC(pl_rw, player_rw, 1); PHYSFS_read(fp, pl_rw, sizeof(player_rw), 1); player_rw_swap(pl_rw, swap); state_player_rw_to_player(pl_rw, &Players[Player_num]); d_free(pl_rw); strcpy( Players[Player_num].callsign, org_callsign ); if (Game_mode & GM_MULTI_COOP) Players[Player_num].objnum = coop_org_objnum; // Restore the weapon states PHYSFS_read(fp, &Primary_weapon, sizeof(sbyte), 1); PHYSFS_read(fp, &Secondary_weapon, sizeof(sbyte), 1); select_weapon(Primary_weapon, 0, 0, 0); select_weapon(Secondary_weapon, 1, 0, 0); // Restore the difficulty level Difficulty_level = PHYSFSX_readSXE32(fp, swap); // Restore the cheats enabled flag game_disable_cheats(); // disable cheats first cheats.enabled = PHYSFSX_readSXE32(fp, swap); cheats.turbo = PHYSFSX_readSXE32(fp, swap); Do_appearance_effect = 0; // Don't do this for middle o' game stuff. ObjectStartLocation = PHYSFS_tell(fp); RetryObjectLoading: //Clear out all the objects from the lvl file for (segnum=0; segnum <= Highest_segment_index; segnum++) Segments[segnum].objects = -1; reset_objects(1); //Read objects, and pop 'em into their respective segments. i = PHYSFSX_readSXE32(fp, swap); Highest_object_index = i-1; if ( !BogusSaturnShit ) //object_read_n_swap(Objects, i, swap, fp); for (i=0; i<=Highest_object_index; i++ ) { object_rw *obj_rw; MALLOC(obj_rw, object_rw, 1); PHYSFS_read(fp, obj_rw, sizeof(object_rw), 1); object_rw_swap(obj_rw, swap); state_object_rw_to_object(obj_rw, &Objects[i]); d_free(obj_rw); } else { for (i=0; i<=Highest_object_index; i++ ) { object_rw *obj_rw; MALLOC(obj_rw, object_rw, 1); // Insert 3 bytes after the read in obj->rtype.pobj_info.alt_textures field. PHYSFS_read(fp, obj_rw, sizeof(object_rw)-3, 1); object_rw_swap(obj_rw, swap); state_object_rw_to_object(obj_rw, &Objects[i]); d_free(obj_rw); Objects[i].rtype.pobj_info.alt_textures = -1; } } for (i=0; i<=Highest_object_index; i++ ) { obj = &Objects[i]; obj->rtype.pobj_info.alt_textures = -1; segnum = obj->segnum; obj->next = obj->prev = obj->segnum = -1; if ( obj->type != OBJ_NONE ) { // Check for a bogus Saturn version!!!! if (!BogusSaturnShit ) { if ( (segnum<0) || (segnum>Highest_segment_index) ) { BogusSaturnShit = 1; PHYSFS_seek( fp, ObjectStartLocation ); goto RetryObjectLoading; } } obj_link(i,segnum); } } special_reset_objects(); //Restore wall info Num_walls = PHYSFSX_readSXE32(fp, swap); // Check for a bogus Saturn version!!!! if (!BogusSaturnShit ) { if ( (Num_walls<0) || (Num_walls>MAX_WALLS) ) { BogusSaturnShit = 1; PHYSFS_seek( fp, ObjectStartLocation ); goto RetryObjectLoading; } } wall_read_n_swap(Walls, Num_walls, swap, fp); // Check for a bogus Saturn version!!!! if (!BogusSaturnShit ) { for (i=0; iHighest_segment_index) || (Walls[i].sidenum<-1) || (Walls[i].sidenum>5) ) { BogusSaturnShit = 1; PHYSFS_seek( fp, ObjectStartLocation ); goto RetryObjectLoading; } } } //Restore door info Num_open_doors = PHYSFSX_readSXE32(fp, swap); active_door_read_n_swap(ActiveDoors, Num_open_doors, swap, fp); //Restore trigger info Num_triggers = PHYSFSX_readSXE32(fp, swap); trigger_read_n_swap(Triggers, Num_triggers, swap, fp); //Restore tmap info for (i=0; i<=Highest_segment_index; i++ ) { for (j=0; j<6; j++ ) { Segments[i].sides[j].wall_num = PHYSFSX_readSXE16(fp, swap); Segments[i].sides[j].tmap_num = PHYSFSX_readSXE16(fp, swap); Segments[i].sides[j].tmap_num2 = PHYSFSX_readSXE16(fp, swap); } } //Restore the fuelcen info Control_center_destroyed = PHYSFSX_readSXE32(fp, swap); Countdown_seconds_left = PHYSFSX_readSXE32(fp, swap); Num_robot_centers = PHYSFSX_readSXE32(fp, swap); matcen_info_read_n_swap(RobotCenters, Num_robot_centers, swap, fp); control_center_triggers_read_n_swap(&ControlCenterTriggers, 1, swap, fp); Num_fuelcenters = PHYSFSX_readSXE32(fp, swap); fuelcen_read_n_swap(Station, Num_fuelcenters, swap, fp); Countdown_timer = 0; for (i = 0; i < Num_fuelcenters; i++) { // NOTE: Usually Descent1 handles countdown by Timer value of the Reactor Station. Since we now use Descent2 code to handle countdown (which we do in case there IS NO Reactor Station which causes potential trouble in Multiplayer), let's find the Reactor here and read the timer from it. if (Station[i].Type == SEGMENT_IS_CONTROLCEN) Countdown_timer = Station[i].Timer; } // Restore the control cen info Control_center_been_hit = PHYSFSX_readSXE32(fp, swap); Control_center_player_been_seen = PHYSFSX_readSXE32(fp, swap); Control_center_next_fire_time = PHYSFSX_readSXE32(fp, swap); Control_center_present = PHYSFSX_readSXE32(fp, swap); Dead_controlcen_object_num = PHYSFSX_readSXE32(fp, swap); if (Control_center_destroyed) Total_countdown_time = Countdown_timer/F0_5; // we do not need to know this, but it should not be 0 either... // Restore the AI state ai_restore_state( fp, version, swap ); // Restore the automap visited info if ( Highest_segment_index+1 > MAX_SEGMENTS_ORIGINAL ) { memset(&Automap_visited, 0, MAX_SEGMENTS); PHYSFS_read(fp, Automap_visited, sizeof(ubyte), Highest_segment_index + 1); } else PHYSFS_read(fp, Automap_visited, sizeof(ubyte), MAX_SEGMENTS_ORIGINAL); // Restore hacked up weapon system stuff. Auto_fire_fusion_cannon_time = 0; Next_laser_fire_time = GameTime64; Next_missile_fire_time = GameTime64; Last_laser_fired_time = GameTime64; state_game_id = 0; if ( version >= 7 ) { state_game_id = PHYSFSX_readSXE32(fp, swap); cheats.rapidfire = PHYSFSX_readSXE32(fp, swap); PHYSFS_seek(fp, PHYSFS_tell(fp) + sizeof(PHYSFS_sint32)); // PHYSFSX_readSXE32(fp, swap); // was Ugly_robot_cheat PHYSFS_seek(fp, PHYSFS_tell(fp) + sizeof(PHYSFS_sint32)); // PHYSFSX_readSXE32(fp, swap); // Ugly_robot_texture cheats.ghostphysics = PHYSFSX_readSXE32(fp, swap); PHYSFS_seek(fp, PHYSFS_tell(fp) + sizeof(PHYSFS_sint32)); // PHYSFSX_readSXE32(fp, swap); // was Lunacy } // Read Coop Info if (Game_mode & GM_MULTI_COOP) { player restore_players[MAX_PLAYERS]; object restore_objects[MAX_PLAYERS]; int coop_got_nplayers = 0; for (i = 0; i < MAX_PLAYERS; i++) { player_rw *pl_rw; object *obj; // prepare arrays for mapping our players below coop_player_got[i] = 0; // read the stored players MALLOC(pl_rw, player_rw, 1); PHYSFS_read(fp, pl_rw, sizeof(player_rw), 1); player_rw_swap(pl_rw, swap); state_player_rw_to_player(pl_rw, &restore_players[i]); d_free(pl_rw); // make all (previous) player objects to ghosts but store them first for later remapping obj = &Objects[restore_players[i].objnum]; if (restore_players[i].connected == CONNECT_PLAYING && obj->type == OBJ_PLAYER) { memcpy(&restore_objects[i], obj, sizeof(object)); obj->type = OBJ_GHOST; multi_reset_player_object(obj); } } for (i = 0; i < MAX_PLAYERS; i++) // copy restored players to the current slots { for (j = 0; j < MAX_PLAYERS; j++) { // map stored players to current players depending on their unique (which we made sure) callsign if (Players[i].connected == CONNECT_PLAYING && restore_players[j].connected == CONNECT_PLAYING && !strcmp(Players[i].callsign, restore_players[j].callsign)) { object *obj; int sav_objnum = Players[i].objnum; memcpy(&Players[i], &restore_players[j], sizeof(player)); Players[i].objnum = sav_objnum; coop_player_got[i] = 1; coop_got_nplayers++; obj = &Objects[Players[i].objnum]; // since a player always uses the same object, we just have to copy the saved object properties to the existing one. i hate you... obj->id = i; // assign player object id to player number obj->control_type = restore_objects[j].control_type; obj->movement_type = restore_objects[j].movement_type; obj->render_type = restore_objects[j].render_type; obj->flags = restore_objects[j].flags; obj->pos = restore_objects[j].pos; obj->orient = restore_objects[j].orient; obj->size = restore_objects[j].size; obj->shields = restore_objects[j].shields; obj->lifeleft = restore_objects[j].lifeleft; obj->mtype.phys_info = restore_objects[j].mtype.phys_info; obj->rtype.pobj_info = restore_objects[j].rtype.pobj_info; // make this restored player object an actual player again obj->type = OBJ_PLAYER; multi_reset_player_object(obj); update_object_seg(obj); } } } PHYSFS_read(fp, &Netgame.mission_title, sizeof(char), MISSION_NAME_LEN+1); PHYSFS_read(fp, &Netgame.mission_name, sizeof(char), 9); Netgame.levelnum = PHYSFSX_readSXE32(fp, swap); PHYSFS_read(fp, &Netgame.difficulty, sizeof(ubyte), 1); PHYSFS_read(fp, &Netgame.game_status, sizeof(ubyte), 1); PHYSFS_read(fp, &Netgame.numplayers, sizeof(ubyte), 1); PHYSFS_read(fp, &Netgame.max_numplayers, sizeof(ubyte), 1); PHYSFS_read(fp, &Netgame.numconnected, sizeof(ubyte), 1); Netgame.level_time = PHYSFSX_readSXE32(fp, swap); for (i = 0; i < MAX_PLAYERS; i++) { Netgame.killed[i] = Players[i].net_killed_total; Netgame.player_score[i] = Players[i].score; Netgame.player_flags[i] = Players[i].flags; } for (i = 0; i < MAX_PLAYERS; i++) // Disconnect connected players not available in this Savegame if (!coop_player_got[i] && Players[i].connected == CONNECT_PLAYING) multi_disconnect_player(i); Viewer = ConsoleObject = &Objects[Players[Player_num].objnum]; // make sure Viewer and ConsoleObject are set up (which we skipped by not using InitPlayerObject but we need since objects changed while loading) special_reset_objects(); // since we juggeled around with objects to remap coop players rebuild the index of free objects } PHYSFS_close(fp); if (Game_wind) if (!window_is_visible(Game_wind)) window_set_visible(Game_wind, 1); reset_time(); return 1; } int state_get_game_id(char *filename) { int version; PHYSFS_file *fp; int swap = 0; // if file is not endian native, have to swap all shorts and ints char id[5], saved_callsign[CALLSIGN_LEN+1]; #ifndef NDEBUG if (GameArg.SysUsePlayersDir && strncmp(filename, "Players/", 8)) Int3(); #endif if (!(Game_mode & GM_MULTI_COOP)) return 0; fp = PHYSFSX_openReadBuffered(filename); if ( !fp ) return 0; //Read id PHYSFS_read(fp, id, sizeof(char) * 4, 1); if ( memcmp( id, dgss_id, 4 )) { PHYSFS_close(fp); return 0; } //Read version //Check for swapped file here, as dgss_id is written as a string (i.e. endian independent) PHYSFS_read(fp, &version, sizeof(int), 1); if (version & 0xffff0000) { swap = 1; version = SWAPINT(version); } if (version < STATE_COMPATIBLE_VERSION) { PHYSFS_close(fp); return 0; } // Read Coop state_game_id to validate the savegame we are about to load matches the others state_game_id = PHYSFSX_readSXE32(fp, swap); PHYSFS_read(fp, &saved_callsign, sizeof(char)*CALLSIGN_LEN+1, 1); if (strcmp(saved_callsign, Players[Player_num].callsign)) // check the callsign of the player who saved this state. It MUST match. If we transferred this savegame from pilot A to pilot B, others won't be able to restore us. So bail out here if this is the case. return 0; return state_game_id; } dxx-rebirth-0.58.1-d1x/main/state.h000066400000000000000000000026661217717257200170010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Prototypes for state saving functions. * */ #ifndef _STATE_H #define _STATE_H #include "playsave.h" int state_save_all(int blind_save); int state_restore_all(int in_game ); extern int state_save_old_game(int slotnum, char * sg_name, player_rw * sg_player, int sg_difficulty_level, int sg_primary_weapon, int sg_secondary_weapon, int sg_next_level_num ); int state_save_all_sub(char *filename, char *desc); int state_restore_all_sub(char *filename); extern uint state_game_id; extern int state_quick_item; int state_get_save_file(char *fname, char * dsc, int blind_save); int state_get_restore_file(char *fname); int state_get_game_id(char *filename); #endif dxx-rebirth-0.58.1-d1x/main/switch.c000066400000000000000000000201441217717257200171440ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * New Triggers and Switches. * */ #include #include #include #include #include "gauges.h" #include "game.h" #include "switch.h" #include "inferno.h" #include "segment.h" #include "dxxerror.h" #include "gameseg.h" #include "wall.h" #include "texmap.h" #include "fuelcen.h" #include "cntrlcen.h" #include "newdemo.h" #include "player.h" #include "endlevel.h" #include "gameseq.h" #include "multi.h" #include "palette.h" #include "byteswap.h" #ifdef EDITOR #include "editor/editor.h" #endif trigger Triggers[MAX_TRIGGERS]; int Num_triggers; //link Links[MAX_WALL_LINKS]; //int Num_links; #ifdef EDITOR fix trigger_time_count=F1_0; //----------------------------------------------------------------- // Initializes all the switches. void trigger_init() { int i; Num_triggers = 0; // Num_links = 0; for (i=0;i MAX_PLAYERS) return 1; if ((Game_mode & GM_MULTI) && (Players[pnum].connected != CONNECT_PLAYING)) // as a host we may want to handle triggers for our clients. to do that properly we must check wether we (host) or client is actually playing. return 1; if (pnum == Player_num) { if (Triggers[trigger_num].flags & TRIGGER_SHIELD_DAMAGE) { Players[Player_num].shields -= Triggers[trigger_num].value; } if (Triggers[trigger_num].flags & TRIGGER_EXIT) { start_endlevel_sequence(); } if (Triggers[trigger_num].flags & TRIGGER_SECRET_EXIT) { if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording Newdemo_state = ND_STATE_PAUSED; #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_endlevel_start(1); #endif #ifdef NETWORK if (Game_mode & GM_NETWORK) multi_do_protocol_frame(1, 1); #endif PlayerFinishedLevel(1); //1 means go to secret level Control_center_destroyed = 0; return 1; } if (Triggers[trigger_num].flags & TRIGGER_ENERGY_DRAIN) { Players[Player_num].energy -= Triggers[trigger_num].value; } } if (Triggers[trigger_num].flags & TRIGGER_CONTROL_DOORS) { do_link(trigger_num); } if (Triggers[trigger_num].flags & TRIGGER_MATCEN) { if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_ROBOTS)) do_matcen(trigger_num); } if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_ON) { do_il_on(trigger_num); } if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_OFF) { do_il_off(trigger_num); } return 0; } //----------------------------------------------------------------- // Checks for a trigger whenever an object hits a trigger side. void check_trigger(segment *seg, short side, short objnum, int shot) { int wall_num, trigger_num, ctrigger_num; segment *csegp; short cside; if ((Game_mode & GM_MULTI) && (Players[Player_num].connected != CONNECT_PLAYING)) // as a host we may want to handle triggers for our clients. so this function may be called when we are not playing. return; if (objnum == Players[Player_num].objnum) { if ( Newdemo_state == ND_STATE_PLAYBACK ) return; wall_num = seg->sides[side].wall_num; if ( wall_num == -1 ) return; trigger_num = Walls[wall_num].trigger; if (trigger_num == -1) return; if (check_trigger_sub(trigger_num, Player_num, shot)) return; if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) { Triggers[trigger_num].flags &= ~TRIGGER_ON; csegp = &Segments[seg->children[side]]; cside = find_connect_side(seg, csegp); Assert(cside != -1); wall_num = csegp->sides[cside].wall_num; if ( wall_num == -1 ) return; ctrigger_num = Walls[wall_num].trigger; Triggers[ctrigger_num].flags &= ~TRIGGER_ON; } #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_trigger(trigger_num); #endif #endif } } void triggers_frame_process() { int i; for (i=0;i= 0) Triggers[i].time -= FrameTime; } /* * reads a v29_trigger structure from a PHYSFS_file */ extern void trigger_read(trigger *t, PHYSFS_file *fp) { int i; t->type = PHYSFSX_readByte(fp); t->flags = PHYSFSX_readShort(fp); t->value = PHYSFSX_readFix(fp); t->time = PHYSFSX_readFix(fp); t->link_num = PHYSFSX_readByte(fp); t->num_links = PHYSFSX_readShort(fp); for (i=0; iseg[i] = PHYSFSX_readShort(fp); for (i=0; iside[i] = PHYSFSX_readShort(fp); } void trigger_swap(trigger *t, int swap) { int i; if (!swap) return; t->flags = SWAPSHORT(t->flags); t->value = SWAPINT(t->value); t->time = SWAPINT(t->time); t->num_links = SWAPSHORT(t->num_links); for (i=0; iseg[i] = SWAPSHORT(t->seg[i]); for (i=0; iside[i] = SWAPSHORT(t->side[i]); } /* * reads n trigger structs from a PHYSFS_file and swaps if specified */ void trigger_read_n_swap(trigger *t, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, t, sizeof(trigger), n); if (swap) for (i = 0; i < n; i++) trigger_swap(&t[i], swap); } void trigger_write(trigger *t, short version, PHYSFS_file *fp) { int i; if (version <= 29) PHYSFSX_writeU8(fp, 0); // unused 'type' else if (version >= 31) { if (t->flags & TRIGGER_CONTROL_DOORS) PHYSFSX_writeU8(fp, 0); // door else if (t->flags & TRIGGER_MATCEN) PHYSFSX_writeU8(fp, 2); // matcen else if (t->flags & TRIGGER_EXIT) PHYSFSX_writeU8(fp, 3); // exit else if (t->flags & TRIGGER_SECRET_EXIT) PHYSFSX_writeU8(fp, 4); // secret exit else if (t->flags & TRIGGER_ILLUSION_OFF) PHYSFSX_writeU8(fp, 5); // illusion off else if (t->flags & TRIGGER_ILLUSION_ON) PHYSFSX_writeU8(fp, 6); // illusion on } if (version <= 30) PHYSFS_writeSLE16(fp, t->flags); else PHYSFSX_writeU8(fp, (t->flags & TRIGGER_ONE_SHOT) ? 2 : 0); // flags if (version >= 30) { PHYSFSX_writeU8(fp, t->num_links); PHYSFSX_writeU8(fp, 0); // t->pad } PHYSFSX_writeFix(fp, t->value); PHYSFSX_writeFix(fp, t->time); if (version <= 29) { PHYSFSX_writeU8(fp, t->link_num); PHYSFS_writeSLE16(fp, t->num_links); } for (i = 0; i < MAX_WALLS_PER_LINK; i++) PHYSFS_writeSLE16(fp, t->seg[i]); for (i = 0; i < MAX_WALLS_PER_LINK; i++) PHYSFS_writeSLE16(fp, t->side[i]); } dxx-rebirth-0.58.1-d1x/main/switch.h000066400000000000000000000063311217717257200171530ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Triggers and Switches. * */ #ifndef _SWITCH_H #define _SWITCH_H #include "inferno.h" #include "segment.h" #define MAX_TRIGGERS 100 #define MAX_WALLS_PER_LINK 10 #define TRIGGER_DEFAULT 2*F1_0 #define MAX_WALL_SWITCHES 50 #define MAX_WALL_LINKS 100 // Trigger flags #define TRIGGER_CONTROL_DOORS 1 // Control Trigger #define TRIGGER_SHIELD_DAMAGE 2 // Shield Damage Trigger #define TRIGGER_ENERGY_DRAIN 4 // Energy Drain Trigger #define TRIGGER_EXIT 8 // End of level Trigger #define TRIGGER_ON 16 // Whether Trigger is active #define TRIGGER_ONE_SHOT 32 // If Trigger can only be triggered once #define TRIGGER_MATCEN 64 // Trigger for materialization centers #define TRIGGER_ILLUSION_OFF 128 // Switch Illusion OFF trigger #define TRIGGER_SECRET_EXIT 256 // Exit to secret level #define TRIGGER_ILLUSION_ON 512 // Switch Illusion ON trigger // Trigger delay times before they can be retriggered (Recharge time) #define TRIGGER_DELAY_DOOR F1_0*1 // 1 second for doors #define TRIGGER_DELAY_ZAPS F1_0/10 // 1/10 second for quickie stuff // New unimplemented trigger ideas #define TRIGGER_CONTROL_ROBOTS 64 // If Trigger is a Door control trigger (Linked) #define CONTROL_ROBOTS 8 // If Trigger modifies robot behavior #define CONTROL_LIGHTS_ON 16 // If Trigger turns on lights in a certain area #define CONTROL_LIGHTS_OFF 32 // If Trigger turns off lights in a certain area typedef struct trigger { sbyte type; short flags; fix value; fix time; sbyte link_num; short num_links; short seg[MAX_WALLS_PER_LINK]; short side[MAX_WALLS_PER_LINK]; } __pack__ trigger; //typedef struct link { // short num_walls; // short seg[MAX_WALLS_PER_LINK]; // short side[MAX_WALLS_PER_LINK]; // } link; extern trigger Triggers[MAX_TRIGGERS]; //extern link Links[MAX_WALL_LINKS]; extern int Num_triggers; //extern int Num_links; extern void trigger_init(); void check_trigger(segment *seg, short side, short objnum, int shot); int check_trigger_sub(int trigger_num, int player_num, int shot); extern void triggers_frame_process(); /* * reads a trigger structure from a PHYSFS_file */ extern void trigger_read(trigger *t, PHYSFS_file *fp); /* * reads n trigger structs from a PHYSFS_file and swaps if specified */ extern void trigger_read_n_swap(trigger *t, int n, int swap, PHYSFS_file *fp); extern void trigger_write(trigger *t, short version, PHYSFS_file *fp); #endif dxx-rebirth-0.58.1-d1x/main/terrain.c000066400000000000000000000253661217717257200173220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Code to render cool external-scene terrain * */ #include #include #include #include "3d.h" #include "dxxerror.h" #include "gr.h" #include "texmap.h" #include "iff.h" #include "u_mem.h" #include "inferno.h" #include "textures.h" #include "render.h" #include "object.h" #include "endlevel.h" #include "fireball.h" #define GRID_MAX_SIZE 64 #define GRID_SCALE i2f(2*20) #define HEIGHT_SCALE f1_0 int grid_w,grid_h; g3s_uvl uvl_list1[] = { {0,0,0}, {f1_0,0,0}, {0,f1_0,0} }; g3s_uvl uvl_list2[] = { {f1_0,0,0}, {f1_0,f1_0,0}, {0,f1_0,0} }; g3s_lrgb lrgb_list1[] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; g3s_lrgb lrgb_list2[] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; ubyte *height_array; ubyte *light_array; #define HEIGHT(_i,_j) (height_array[(_i)*grid_w+(_j)]) #define LIGHT(_i,_j) light_array[(_i)*grid_w+(_j)] //!!#define HEIGHT(_i,_j) height_array[(grid_h-1-j)*grid_w+(_i)] //!!#define LIGHT(_i,_j) light_array[(grid_h-1-j)*grid_w+(_i)] #define LIGHTVAL(_i,_j) (((fix) LIGHT(_i,_j))<<8) g3s_point save_row[GRID_MAX_SIZE]; vms_vector start_point; grs_bitmap *terrain_bm; void build_light_table(); int terrain_outline=0; int org_i,org_j; int mine_tiles_drawn; //flags to tell if all 4 tiles under mine have drawn void draw_cell(int i,int j,g3s_point *p0,g3s_point *p1,g3s_point *p2,g3s_point *p3) { g3s_point *pointlist[3]; pointlist[0] = p0; pointlist[1] = p1; pointlist[2] = p3; lrgb_list1[0].r = lrgb_list1[0].g = lrgb_list1[0].b = uvl_list1[0].l = LIGHTVAL(i,j); lrgb_list1[1].r = lrgb_list1[1].g = lrgb_list1[1].b = uvl_list1[1].l = LIGHTVAL(i,j+1); lrgb_list1[2].r = lrgb_list1[2].g = lrgb_list1[2].b = uvl_list1[2].l = LIGHTVAL(i+1,j); uvl_list1[0].u = (i)*f1_0/4; uvl_list1[0].v = (j)*f1_0/4; uvl_list1[1].u = (i)*f1_0/4; uvl_list1[1].v = (j+1)*f1_0/4; uvl_list1[2].u = (i+1)*f1_0/4; uvl_list1[2].v = (j)*f1_0/4; g3_check_and_draw_tmap(3,pointlist,uvl_list1,lrgb_list1,terrain_bm,NULL,NULL); if (terrain_outline) { int lsave=Lighting_on; Lighting_on=0; gr_setcolor(BM_XRGB(31,0,0)); g3_draw_line(pointlist[0],pointlist[1]); g3_draw_line(pointlist[2],pointlist[0]); Lighting_on=lsave; } pointlist[0] = p1; pointlist[1] = p2; lrgb_list2[0].r = lrgb_list2[0].g = lrgb_list2[0].b = uvl_list2[0].l = LIGHTVAL(i,j+1); lrgb_list2[1].r = lrgb_list2[1].g = lrgb_list2[1].b = uvl_list2[1].l = LIGHTVAL(i+1,j+1); lrgb_list2[2].r = lrgb_list2[2].g = lrgb_list2[2].b = uvl_list2[2].l = LIGHTVAL(i+1,j); uvl_list2[0].u = (i)*f1_0/4; uvl_list2[0].v = (j+1)*f1_0/4; uvl_list2[1].u = (i+1)*f1_0/4; uvl_list2[1].v = (j+1)*f1_0/4; uvl_list2[2].u = (i+1)*f1_0/4; uvl_list2[2].v = (j)*f1_0/4; g3_check_and_draw_tmap(3,pointlist,uvl_list2,lrgb_list2,terrain_bm,NULL,NULL); if (terrain_outline) { int lsave=Lighting_on; Lighting_on=0; gr_setcolor(BM_XRGB(31,0,0)); g3_draw_line(pointlist[0],pointlist[1]); g3_draw_line(pointlist[1],pointlist[2]); g3_draw_line(pointlist[2],pointlist[0]); Lighting_on=lsave; } if (i==org_i && j==org_j) mine_tiles_drawn |= 1; if (i==org_i-1 && j==org_j) mine_tiles_drawn |= 2; if (i==org_i && j==org_j-1) mine_tiles_drawn |= 4; if (i==org_i-1 && j==org_j-1) mine_tiles_drawn |= 8; if (mine_tiles_drawn == 0xf) { render_mine(exit_segnum,0); //draw_exit_model(); mine_tiles_drawn=-1; //if (ext_expl_playing) // draw_fireball(&external_explosion); } } vms_vector y_cache[256]; ubyte yc_flags[256]; extern vms_matrix surface_orient; vms_vector *get_dy_vec(int h) { vms_vector *dyp; dyp = &y_cache[h]; if (!yc_flags[h]) { vms_vector tv; //@@g3_rotate_delta_y(dyp,h*HEIGHT_SCALE); vm_vec_copy_scale(&tv,&surface_orient.uvec,h*HEIGHT_SCALE); g3_rotate_delta_vec(dyp,&tv); yc_flags[h] = 1; } return dyp; } int im=1; void render_terrain(vms_vector *org_point,int org_2dx,int org_2dy) { vms_vector delta_i,delta_j; //delta_y; g3s_point p,last_p,save_p_low,save_p_high; g3s_point last_p2; int i=0,j=0; int low_i=0,high_i=0,low_j=0,high_j=0; int viewer_i=0,viewer_j=0; vms_vector tv; vm_vec_zero(&delta_i);vm_vec_zero(&delta_j);vm_vec_zero(&tv); mine_tiles_drawn = 0; //clear flags org_i = org_2dy; org_j = org_2dx; low_i = 0; high_i = grid_w-1; low_j = 0; high_j = grid_h-1; //@@start_point.x = org_point->x - GRID_SCALE*(org_i - low_i); //@@start_point.z = org_point->z - GRID_SCALE*(org_j - low_j); //@@start_point.y = org_point->y; memset(yc_flags,0,256); //Lighting_on = 0; Interpolation_method = im; vm_vec_copy_scale(&tv,&surface_orient.rvec,GRID_SCALE); g3_rotate_delta_vec(&delta_i,&tv); vm_vec_copy_scale(&tv,&surface_orient.fvec,GRID_SCALE); g3_rotate_delta_vec(&delta_j,&tv); vm_vec_scale_add(&start_point,org_point,&surface_orient.rvec,-(org_i - low_i)*GRID_SCALE); vm_vec_scale_add2(&start_point,&surface_orient.fvec,-(org_j - low_j)*GRID_SCALE); vm_vec_sub(&tv,&Viewer->pos,&start_point); viewer_i = vm_vec_dot(&tv,&surface_orient.rvec) / GRID_SCALE; viewer_j = vm_vec_dot(&tv,&surface_orient.fvec) / GRID_SCALE; g3_rotate_point(&last_p,&start_point); save_p_low = last_p; for (j=low_j;j<=high_j;j++) { g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(low_i,j))); if (j==high_j) save_p_high = last_p; else g3_add_delta_vec(&last_p,&last_p,&delta_j); } for (i=low_i;i=viewer_j;j--) { g3s_point p2; g3_add_delta_vec(&p,&last_p,&delta_j); g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i+1,j))); draw_cell(i,j,&save_row[j],&save_row[j+1],&last_p2,&p2); last_p = p; save_row[j+1] = last_p2; last_p2 = p2; } save_row[j+1] = last_p2; vm_vec_negate(&delta_j); //restore sign of j } //now do i from other end vm_vec_negate(&delta_i); //going the other way now... //@@start_point.x += (high_i-low_i)*GRID_SCALE; vm_vec_scale_add2(&start_point,&surface_orient.rvec,(high_i-low_i)*GRID_SCALE); g3_rotate_point(&last_p,&start_point); save_p_low = last_p; for (j=low_j;j<=high_j;j++) { g3_add_delta_vec(&save_row[j],&last_p,get_dy_vec(HEIGHT(high_i,j))); if (j==high_j) save_p_high = last_p; else g3_add_delta_vec(&last_p,&last_p,&delta_j); } for (i=high_i-1;i>=viewer_i;i--) { g3_add_delta_vec(&save_p_low,&save_p_low,&delta_i); last_p = save_p_low; g3_add_delta_vec(&last_p2,&last_p,get_dy_vec(HEIGHT(i,low_j))); for (j=low_j;j=viewer_j;j--) { g3s_point p2; g3_add_delta_vec(&p,&last_p,&delta_j); g3_add_delta_vec(&p2,&p,get_dy_vec(HEIGHT(i,j))); draw_cell(i,j,&p2,&last_p2,&save_row[j+1],&save_row[j]); last_p = p; save_row[j+1] = last_p2; last_p2 = p2; } save_row[j+1] = last_p2; vm_vec_negate(&delta_j); //restore sign of j } } void free_height_array() { if (height_array) d_free(height_array); } void load_terrain(char *filename) { grs_bitmap height_bitmap; int iff_error; int i,j; ubyte h,min_h,max_h; iff_error = iff_read_bitmap(filename,&height_bitmap,BM_LINEAR,NULL); if (iff_error != IFF_NO_ERROR) { Error("File %s - IFF error: %s",filename,iff_errormsg(iff_error)); } if (height_array) d_free(height_array); grid_w = height_bitmap.bm_w; grid_h = height_bitmap.bm_h; Assert(grid_w <= GRID_MAX_SIZE); Assert(grid_h <= GRID_MAX_SIZE); height_array = height_bitmap.bm_data; max_h=0; min_h=255; for (i=0;i max_h) max_h = h; if (h < min_h) min_h = h; } for (i=0;i= grid_h) i = grid_h - 1; if (i == grid_h - 1 && j >= grid_w) j = grid_w - 1; // end additions by adb p->x = GRID_SCALE*i; p->z = GRID_SCALE*j; p->y = HEIGHT(i,j)*HEIGHT_SCALE; } vms_vector light = {0x2e14,0xe8f5,0x5eb8}; fix get_face_light(vms_vector *p0,vms_vector *p1,vms_vector *p2) { vms_vector norm; vm_vec_normal(&norm,p0,p1,p2); return -vm_vec_dot(&norm,&light); } fix get_avg_light(int i,int j) { vms_vector pp,p[6]; fix sum; int f; get_pnt(&pp,i,j); get_pnt(&p[0],i-1,j); get_pnt(&p[1],i,j-1); get_pnt(&p[2],i+1,j-1); get_pnt(&p[3],i+1,j); get_pnt(&p[4],i,j+1); get_pnt(&p[5],i-1,j+1); for (f=0,sum=0;f<6;f++) sum += get_face_light(&pp,&p[f],&p[(f+1)%5]); return sum/6; } void free_light_table() { if (light_array) d_free(light_array); } void build_light_table() { int i,j; fix l,l2,min_l=0x7fffffff,max_l=0; if (light_array) d_free(light_array); MALLOC(light_array,ubyte,grid_w*grid_h); memset(light_array, 0, grid_w*grid_h); for (i=1;i max_l) max_l = l; if (l < min_l) min_l = l; } for (i=1;i>8; continue; } l2 = fixdiv((l-min_l),(max_l-min_l)); if (l2==f1_0) l2--; LIGHT(i,j) = l2>>8; } } dxx-rebirth-0.58.1-d1x/main/terrain.h000066400000000000000000000017061217717257200173170ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for terrain.c * */ #ifndef _TERRAIN_H #define _TERRAIN_H void free_light_table(); void free_height_array(); void load_terrain(char *filename); void render_terrain(vms_vector *org, int org_i, int org_j); #endif dxx-rebirth-0.58.1-d1x/main/texmerge.c000066400000000000000000000201351217717257200174630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to cache merged textures. * */ #include #include "gr.h" #include "dxxerror.h" #include "game.h" #include "textures.h" #include "rle.h" #include "piggy.h" #include "timer.h" //resending textures into video ram is very slow, so cache more (worst case, the ogl driver will swap out some itself, probably doing a better job) -MM #ifdef OGL #include "ogl_init.h" #define MAX_NUM_CACHE_BITMAPS 200 #else #define MAX_NUM_CACHE_BITMAPS 50 #endif void merge_textures_new( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data ); void merge_textures_super_xparent( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data ); //static grs_bitmap * cache_bitmaps[MAX_NUM_CACHE_BITMAPS]; typedef struct { grs_bitmap * bitmap; grs_bitmap * bottom_bmp; grs_bitmap * top_bmp; int orient; fix64 last_time_used; } TEXTURE_CACHE; static TEXTURE_CACHE Cache[MAX_NUM_CACHE_BITMAPS]; static int num_cache_entries = 0; static int cache_hits = 0; static int cache_misses = 0; void texmerge_close(); //---------------------------------------------------------------------- int texmerge_init(int num_cached_textures) { int i; if ( num_cached_textures <= MAX_NUM_CACHE_BITMAPS ) num_cache_entries = num_cached_textures; else num_cache_entries = MAX_NUM_CACHE_BITMAPS; for (i=0; i>14) & 3; least_recently_used = 0; lowest_time_used = Cache[0].last_time_used; for (i=0; i -1) && (Cache[i].top_bmp==bitmap_top) && (Cache[i].bottom_bmp==bitmap_bottom) && (Cache[i].orient==orient )) { cache_hits++; Cache[i].last_time_used = timer_query(); return Cache[i].bitmap; } if ( Cache[i].last_time_used < lowest_time_used ) { lowest_time_used = Cache[i].last_time_used; least_recently_used = i; } } //---- Page out the LRU bitmap; cache_misses++; // Make sure the bitmaps are paged in... piggy_page_flushed = 0; PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]); PIGGY_PAGE_IN(Textures[tmap_bottom]); if (piggy_page_flushed) { // If cache got flushed, re-read 'em. piggy_page_flushed = 0; PIGGY_PAGE_IN(Textures[tmap_top&0x3FFF]); PIGGY_PAGE_IN(Textures[tmap_bottom]); } Assert( piggy_page_flushed == 0 ); if (bitmap_bottom->bm_w != bitmap_bottom->bm_h || bitmap_top->bm_w != bitmap_top->bm_h) Error("Texture width != texture height!\n"); if (bitmap_bottom->bm_w != bitmap_top->bm_w || bitmap_bottom->bm_h != bitmap_top->bm_h) Error("Top and Bottom textures have different size!\n"); if (Cache[least_recently_used].bitmap != NULL) gr_free_bitmap(Cache[least_recently_used].bitmap); Cache[least_recently_used].bitmap = gr_create_bitmap(bitmap_bottom->bm_w, bitmap_bottom->bm_h); #ifdef OGL ogl_freebmtexture(Cache[least_recently_used].bitmap); #endif if (bitmap_top->bm_flags & BM_FLAG_SUPER_TRANSPARENT) { merge_textures_super_xparent( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data ); gr_set_bitmap_flags (Cache[least_recently_used].bitmap, BM_FLAG_TRANSPARENT); Cache[least_recently_used].bitmap->avg_color = bitmap_top->avg_color; } else { merge_textures_new( orient, bitmap_bottom, bitmap_top, Cache[least_recently_used].bitmap->bm_data ); Cache[least_recently_used].bitmap->bm_flags = bitmap_bottom->bm_flags & (~BM_FLAG_RLE); Cache[least_recently_used].bitmap->avg_color = bitmap_bottom->avg_color; } Cache[least_recently_used].top_bmp = bitmap_top; Cache[least_recently_used].bottom_bmp = bitmap_bottom; Cache[least_recently_used].last_time_used = timer_query(); Cache[least_recently_used].orient = orient; return Cache[least_recently_used].bitmap; } void merge_textures_new( int type, grs_bitmap * bottom_bmp, grs_bitmap * top_bmp, ubyte * dest_data ) { ubyte * top_data, *bottom_data, c = 0; int x, y, wh; if ( top_bmp->bm_flags & BM_FLAG_RLE ) top_bmp = rle_expand_texture(top_bmp); if ( bottom_bmp->bm_flags & BM_FLAG_RLE ) bottom_bmp = rle_expand_texture(bottom_bmp); top_data = top_bmp->bm_data; bottom_data = bottom_bmp->bm_data; wh = bottom_bmp->bm_w; switch( type ) { case 0: // Normal for (y=0; ybm_flags & BM_FLAG_RLE ) top_bmp = rle_expand_texture(top_bmp); if ( bottom_bmp->bm_flags & BM_FLAG_RLE ) bottom_bmp = rle_expand_texture(bottom_bmp); top_data = top_bmp->bm_data; bottom_data = bottom_bmp->bm_data; wh = bottom_bmp->bm_w; switch( type ) { case 0: // Normal for (y=0; y #include #include "physfsx.h" #include "pstypes.h" #include "u_mem.h" #include "dxxerror.h" #include "inferno.h" #include "text.h" #include "args.h" char *text; char *Text_string[N_TEXT_STRINGS]; void free_text() { d_free(Text_string[330]); d_free(text); } // rotates a byte left one bit, preserving the bit falling off the right void encode_rotate_left(char *c) { int found; found = 0; if (*c & 0x80) found = 1; *c = *c << 1; if (found) *c |= 0x01; } #define BITMAP_TBL_XOR 0xD3 //decode an encoded line of text of bitmaps.tbl void decode_text_line(char *p) { for (;*p;p++) { encode_rotate_left(p); *p = *p ^ BITMAP_TBL_XOR; encode_rotate_left(p); } } // decode buffer of text, preserves newlines void decode_text(char *buf, int len) { char *ptr; int i; for (i = 0, ptr = buf; i < len; i++, ptr++) { if (*ptr != '\n') { encode_rotate_left(ptr); *ptr = *ptr ^ BITMAP_TBL_XOR; encode_rotate_left(ptr); } } } //load all the text strings for Descent void load_text() { PHYSFS_file *tfile; PHYSFS_file *ifile; int len,i, have_binary = 0; char *tptr; char *filename="descent.tex"; char *extra_strings[] = { "done", "I am a", "CHEATER!", "Loading Data", "ALT-F2\t Save Game", "ALT-F3\t Load Game", "Only in Registered version!", "Concussion", "Homing", "ProxBomb", "Smart", "Mega", "Mission '%s' not found.\nYou must have this mission\nfile in order to playback\nthis demo.", "All player callsigns on screen", "There is already a game\nin progress with that name", "This mission is designated\nAnarchy-only", "Force level start", "Quitting now means ending the\nentire netgame\n\nAre you sure?", "The mission for that netgame\nis not installed on your\nsystem. Cannot join.", "Start Multiplayer Game\n\nSelect mission", "Error loading mission file", "Custom (return to set)", "Base address (in Hex)", "IRQ Number", "Reset to Default", "Valid IRQ values are 2-7", "No UART was detected\nat those settings", "You will pay dearly for that!", "Revenge is mine!!", "Man I'm good!", "Its almost too easy!", " Mission:", "+/- Changes viewing distance", "Alternate exit found!\n\nProceeding to Secret Level!", "Show all players on automap", "Killed by a robot", "Baud", "A consistency error has been\ndetected in your network connection.\nCheck you hardware and re-join", "Press any key to continue (Print Screen to save screenshot)", "An error occured while writing\ndemo. Demo is likely corrupted.\nEnter demo name now or\npress ESC to delete demo.", "The main reactor is invulnerable for", "The level being loaded is not\navailable in Destination Saturn.\nUnable to continue demo playback.\n\nPress any key to continue.", "Reactor life", "min", "Current IPX Socket is default", "This program requires MS-DOS 5.0 or higher.\nYou are using MS-DOS", "You can use the -nodoscheck command line\nswitch to override this check, but it\nmay have unpredictable results, namely\nwith DOS file error handling.\n", "Not enough file handles!", "of the necessary file handles\nthat Descent requires to execute properly. You will\nneed to increase the FILES=n line in your config.sys.", "If you are running with a clean boot, then you will need\nto create a CONFIG.SYS file in your root directory, with\nthe line FILES=15 in it. If you need help with this,\ncontact Interplay technical support.", "You may also run with the -nofilecheck command line option\nthat will disable this check, but you might get errors\nwhen loading saved games or playing demos.", "Available memory", "more bytes of DOS memory needed!", "more bytes of virtual memory needed. Reconfigure VMM.", "more bytes of extended/expanded memory needed!", "Or else you you need to use virtual memory (See README.TXT)", "more bytes of physical memory needed!", "Check to see that your virtual memory settings allow\nyou to use all of your physical memory (See README.TXT)", "Initializing DPMI services", "Initializing critical error handler", "Enables Virtual I/O Iglasses! stereo display", "Enables Iglasses! head tracking via COM port", "Enables Kasan's 3dMax stereo display in low res.", "3DBios must be installed for 3dMax operation.", "Enables Kasan's 3dMax stereo display in high res", "Press any key for more options...", "Enables dynamic socket changing", "Disables the file handles check", "Getting settings from DESCENT.CFG...", "Initializing timer system...", "Initializing keyboard handler...", "Initializing mouse handler...", "Mouse support disabled...", "Initializing joystick handler...", "Slow joystick reading enabled...", "Polled joystick reading enabled...", "BIOS joystick reading enabled...", "Joystick support disabled...", "Initializing divide by zero handler...", "Initializing network...", "Using IPX network support on channel", "No IPX compatible network found.", "Error opening socket", "Not enough low memory for IPX buffers.", "Error initializing IPX. Error code:", "Network support disabled...", "Initializing graphics system...", "SOUND: Error opening", "SOUND: Error locking down instruments", "SOUND: (HMI)", "SOUND: Error locking down drums", "SOUND: Error locking midi track map!", "SOUND: Error locking midi callback function!", "Using external control:", "Invalid serial port parameter for -itrak!", "Initializing i-glasses! head tracking on serial port %d", "Make sure the glasses are turned on!", "Press ESC to abort", "Failed to open serial port. Status =", "Message", "Macro", "Error locking serial interrupt routine!", "Error locking serial port data!", "Robots are normal", "Robots move fast, fire seldom", "Robot painting OFF", "Robot painting with texture %d" }; if (GameArg.DbgAltTex) filename = GameArg.DbgAltTex; if ((tfile = PHYSFSX_openReadBuffered(filename)) == NULL) { filename="descent.txb"; if ((ifile = PHYSFSX_openReadBuffered(filename)) == NULL) { Error("Cannot open file DESCENT.TEX or DESCENT.TXB"); return; } have_binary = 1; len = PHYSFS_fileLength(ifile); //edited 05/17/99 Matt Mueller - malloc an extra byte, and null terminate. MALLOC(text,char,len+1); PHYSFS_read(ifile,text,1,len); text[len]=0; //end edit -MM PHYSFS_close(ifile); } else { int c; char * p; len = PHYSFS_fileLength(tfile); //edited 05/17/99 Matt Mueller - malloc an extra byte, and null terminate. MALLOC(text,char,len+1); //fread(text,1,len,tfile); p = text; do { c = PHYSFSX_fgetc( tfile ); if ( c != 13 ) *p++ = c; } while ( c!=EOF ); *p=0; //end edit -MM PHYSFS_close(tfile); } for (i=0,tptr=text;i= N_TEXT_STRINGS_MIN) // account for non-registered 1.4/1.5 text files { Text_string[i-1] = extra_strings[i - N_TEXT_STRINGS_MIN - 1]; Text_string[i] = extra_strings[i - N_TEXT_STRINGS_MIN]; continue; } else if (!tptr && i < N_TEXT_STRINGS_MIN) { Error("Not enough strings in text file - expecting %d (or at least %d), found %d",N_TEXT_STRINGS,N_TEXT_STRINGS_MIN,i); } Text_string[i] = tptr; tptr = strchr(tptr,'\n'); if ( tptr ) *tptr++ = 0; if (have_binary) decode_text_line(Text_string[i]); //scan for special chars (like \n) for (p=Text_string[i];(p=strchr(p,'\\'));) { char newchar; if (p[1] == 'n') newchar = '\n'; else if (p[1] == 't') newchar = '\t'; else if (p[1] == '\\') newchar = '\\'; else Error("Unsupported key sequence <\\%c> on line %d of file <%s>",p[1],i+1,filename); p[0] = newchar; // strcpy(p+1,p+2); MALLOC(buf,char,len+1); strcpy(buf,p+2); strcpy(p+1,buf); d_free(buf); p++; } switch(i) { char *extra; char *str; case 116: if (!d_stricmp(Text_string[i], "SPREADFIRE")) // This string is too long to fit in the cockpit-box { memset(Text_string[i], '\0', sizeof(char)*(strlen(Text_string[i])+1)); strncpy(Text_string[i], "SPREAD", sizeof(char)*6); } break; case 330: extra = "\n converts format\nIntel <-> PowerPC"; str = d_malloc(strlen(Text_string[i]) + strlen(extra) + 1); if (!str) break; strcpy(str, Text_string[i]); strcat(str, extra); Text_string[i] = str; break; } } //Assert(tptr==text+len || tptr==text+len-2); } dxx-rebirth-0.58.1-d1x/main/text.h000066400000000000000000001322701217717257200166400ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for text.c, including symbolics for text messages * */ #ifndef _TEXT_H #define _TEXT_H //Array of pointers to text extern char *Text_string[]; static inline char *dxx_gettext(unsigned idx, const char *text) { #ifdef USE_BUILTIN_ENGLISH_TEXT_STRINGS (void)idx; return (char *)text; #else (void)text; return Text_string[idx]; #endif } //Symbolic constants for all the strings #define TXT_NEW_GAME dxx_gettext(0, "New game") #define TXT_VIEW_SCORES dxx_gettext(1, "High scores") #define TXT_QUIT dxx_gettext(2, "Quit") #define TXT_CANNOT_SET_SCREEN dxx_gettext(3, "Cannot set screen mode for game") #define TXT_NO_JOYSTICK dxx_gettext(4, "No joystick detected") #define TXT_REQUIRES_VGA dxx_gettext(5, "This game requires a VGA adapter.") #define TXT_HELP dxx_gettext(6, "Type 'DESCENT -help' for a list of command-line options.") #define TXT_THANKS dxx_gettext(7, "Thank-you for playing DESCENT!") #define TXT_SOUND_DISABLED dxx_gettext(8, "Sound disabled.") #define TXT_CANT_INIT_GFX dxx_gettext(9, "Can't initialize graphics, error=%d") #define TXT_EXTRA_LIFE dxx_gettext(10, "EXTRA LIFE!") #define TXT_COPYRIGHT dxx_gettext(11, "Copyright (C) 1994, 1995 Parallax Software Corporation") #define TXT_BLUE dxx_gettext(12, "BLUE") #define TXT_RED dxx_gettext(13, "RED") #define TXT_YELLOW dxx_gettext(14, "YELLOW") #define TXT_ACCESS_DENIED dxx_gettext(15, "Access denied") #define TXT_ACCESS_GRANTED dxx_gettext(16, "Access granted") #define TXT_BOOSTED_TO dxx_gettext(17, "boosted to") #define TXT_ENERGY dxx_gettext(18, "Energy") #define TXT_SHIELD dxx_gettext(19, "Shield") #define TXT_LASER dxx_gettext(20, "Laser") #define TXT_MAXED_OUT dxx_gettext(21, "Your %s is maxed out!") #define TXT_QUAD_LASERS dxx_gettext(22, "Quad Lasers") #define TXT_ALREADY_HAVE dxx_gettext(23, "You already have") #define TXT_VULCAN_AMMO dxx_gettext(24, "Vulcan Ammo") #define TXT_VULCAN_ROUNDS dxx_gettext(25, "Vulcan Rounds") #define TXT_ALREADY_ARE dxx_gettext(26, "You already are") #define TXT_CLOAKED dxx_gettext(27, "Cloaked") #define TXT_CLOAKING_DEVICE dxx_gettext(28, "Cloaking Device") #define TXT_INVULNERABLE dxx_gettext(29, "Invulnerable") #define TXT_INVULNERABILITY dxx_gettext(30, "Invulnerability") #define TXT_CREATE_NEW dxx_gettext(31, "") #define TXT_YES dxx_gettext(32, "Yes") #define TXT_NO dxx_gettext(33, "No") #define TXT_OK dxx_gettext(34, "Ok") #define TXT_NO_DEMO_FILES dxx_gettext(35, "No Demo Files found.") #define TXT_USE_F5 dxx_gettext(36, "Use F5") #define TXT_TO_CREATE_ONE dxx_gettext(37, "during game to create one.") #define TXT_NO_FILES_MATCHING dxx_gettext(38, "No files matching") #define TXT_WERE_FOUND dxx_gettext(39, "were found!") #define TXT_DELETE_PILOT dxx_gettext(40, "Delete Pilot:") #define TXT_DELETE_DEMO dxx_gettext(41, "Delete Demo:") #define TXT_COULDNT dxx_gettext(42, "Couldn't") #define TXT_EXIT_SEQUENCE dxx_gettext(43, "Exiting the mine!") #define TXT_WARNING dxx_gettext(44, "Warning!") #define TXT_UNABLE_TO_OPEN dxx_gettext(45, "Unable to open") #define TXT_COOL_SAYING dxx_gettext(46, "Enter your cool saying.\nPress ESC when done.") #define TXT_HIGH_SCORE dxx_gettext(47, "HIGH SCORE!") #define TXT_YOU_PLACED dxx_gettext(48, "You placed") #define TXT_YOU_PLACED_1ST dxx_gettext(49, "You placed 1st!") #define TXT_HIGH_SCORES dxx_gettext(50, "HIGH SCORES") #define TXT_NAME dxx_gettext(51, "Name") #define TXT_SCORE dxx_gettext(52, "Score") #define TXT_SKILL dxx_gettext(53, "Skill") #define TXT_LEVELS dxx_gettext(54, "Levels") #define TXT_TIME dxx_gettext(55, "Time") #define TXT_REGISTER_DESCENT dxx_gettext(56, "CD-Enhanced Descent Coming Summer '95!") #define TXT_1ST dxx_gettext(57, "1st") #define TXT_2ND dxx_gettext(58, "2nd") #define TXT_3RD dxx_gettext(59, "3rd") #define TXT_4TH dxx_gettext(60, "4th") #define TXT_5TH dxx_gettext(61, "5th") #define TXT_6TH dxx_gettext(62, "6th") #define TXT_7TH dxx_gettext(63, "7th") #define TXT_8TH dxx_gettext(64, "8th") #define TXT_9TH dxx_gettext(65, "9th") #define TXT_10TH dxx_gettext(66, "10th") #define TXT_EMPTY dxx_gettext(67, "-empty-") #define TXT_KILLED dxx_gettext(68, "killed") #define TXT_SUICIDE dxx_gettext(69, "committed suicide!") #define TXT_YOU dxx_gettext(70, "You") #define TXT_YOURSELF dxx_gettext(71, "yourself") #define TXT_NO_MACRO dxx_gettext(72, "That macro is not defined.") #define TXT_SENDING dxx_gettext(73, "Sending") #define TXT_SEND_MESSAGE dxx_gettext(74, "Send Message:") #define TXT_SAYS dxx_gettext(75, "says") #define TXT_TELLS_YOU dxx_gettext(76, "tells you") #define TXT_HAS_DEST_CONTROL dxx_gettext(77, "has destroyed the main reactor!") #define TXT_CONTROL_DESTROYED dxx_gettext(78, "The main reactor has been destroyed!") #define TXT_HAS_ESCAPED dxx_gettext(79, "has escaped the mine!") #define TXT_HAS_FOUND_SECRET dxx_gettext(80, "has found the secret level!") #define TXT_HAS_LEFT_THE_GAME dxx_gettext(81, "has left the game!") #define TXT_YOU_ARE_ONLY dxx_gettext(82, "You are the only person\nremaining in this netgame.") #define TXT_OPPONENT_LEFT dxx_gettext(83, "Your opponent has left.\nReturning to menu.") #define TXT_YOU_DEST_CONTROL dxx_gettext(84, "You destroyed the main reactor!") #define TXT_DEFINE_MACRO dxx_gettext(85, "Define Macro #") #define TXT_MESSAGE_SENT_TO dxx_gettext(86, "Message sent to") #define TXT_NOBODY dxx_gettext(87, "Nobody.") #define TXT_PAUSE dxx_gettext(88, "Pause") #define TXT_CANT_PAUSE dxx_gettext(89, "You can't pause in a multiplayer game!") #define TXT_HELP_ESC dxx_gettext(90, "ESC\t Abort Game") #define TXT_HELP_F2 dxx_gettext(91, "F2\t Options menu") #define TXT_HELP_F3 dxx_gettext(92, "F3\t Toggle cockpit") #define TXT_HELP_F4 dxx_gettext(93, "F4\t Calibrate joystick") #define TXT_HELP_F5 dxx_gettext(94, "F5\t Toggle recording") #define TXT_HELP_PAUSE dxx_gettext(95, "Pause\t Pause") #define TXT_HELP_MINUSPLUS dxx_gettext(96, "-/+\t Change screen size") #define TXT_HELP_PRTSCN dxx_gettext(97, "PrintScrn\t Save screen shot") #define TXT_HELP_1TO5 dxx_gettext(98, "1-5\t Select primary weapon") #define TXT_HELP_6TO10 dxx_gettext(99, "6-0\t Select secondary weapon") #define TXT_HELP_TO_VIEW dxx_gettext(100, " To view control keys, select\nconfiguration in options menu") #define TXT_KEYS dxx_gettext(101, "KEYS") #define TXT_ABORT_AUTODEMO dxx_gettext(102, "Abort Autodemo?") #define TXT_ABORT_GAME dxx_gettext(103, "Abort Game?") #define TXT_W_LASER dxx_gettext(104, "Laser Cannon") #define TXT_W_VULCAN dxx_gettext(105, "Vulcan Cannon") #define TXT_W_SPREADFIRE dxx_gettext(106, "Spreadfire Cannon") #define TXT_W_PLASMA dxx_gettext(107, "Plasma Cannon") #define TXT_W_FUSION dxx_gettext(108, "Fusion Cannon") #define TXT_W_C_MISSILE dxx_gettext(109, "Concussion Missile") #define TXT_W_H_MISSILE dxx_gettext(110, "Homing Missile") #define TXT_W_P_BOMB dxx_gettext(111, "Proximity Bomb") #define TXT_W_S_MISSILE dxx_gettext(112, "Smart Missile") #define TXT_W_M_MISSILE dxx_gettext(113, "Mega Missile") #define TXT_W_LASER_S dxx_gettext(114, "Laser") #define TXT_W_VULCAN_S dxx_gettext(115, "Vulcan") #define TXT_W_SPREADFIRE_S dxx_gettext(116, "SPREAD") #define TXT_W_PLASMA_S dxx_gettext(117, "Plasma") #define TXT_W_FUSION_S dxx_gettext(118, "Fusion") #define TXT_W_C_MISSILE_S dxx_gettext(119, "Concsn\nMissile") #define TXT_W_H_MISSILE_S dxx_gettext(120, "Homing\nMissile") #define TXT_W_P_BOMB_S dxx_gettext(121, "Proxim.\nBomb") #define TXT_W_S_MISSILE_S dxx_gettext(122, "Smart\nMissile") #define TXT_W_M_MISSILE_S dxx_gettext(123, "Mega\nMissile") #define TXT_SELECTED dxx_gettext(124, "selected!") #define TXT_DONT_HAVE dxx_gettext(125, "You don't have the") #define TXT_DONT_HAVE_AMMO dxx_gettext(126, "You don't have ammo for the") #define TXT_HAVE_NO dxx_gettext(127, "You have no") #define TXT_S dxx_gettext(128, "s") #define TXT_SX dxx_gettext(129, "s!") #define TXT_NO_PRIMARY dxx_gettext(130, "No primary weapons available") #define TXT_ALREADY_HAVE_THE dxx_gettext(131, "You already have the") #define TXT_CANT_OPEN_DOOR dxx_gettext(132, "You cannot open this door.") #define TXT_MOVE_JOYSTICK dxx_gettext(133, "Move joystick") #define TXT_TO_UL dxx_gettext(134, "to\nthe upper-left corner") #define TXT_ANY_BUTTON dxx_gettext(135, "and press any button.") #define TXT_JOYSTICK dxx_gettext(136, "joystick") #define TXT_UPPER_LEFT dxx_gettext(137, "upper-left") #define TXT_TO_LR dxx_gettext(138, "to\nthe lower-right corner") #define TXT_LOWER_RIGHT dxx_gettext(139, "lower-right") #define TXT_TO_C dxx_gettext(140, "to\nthe center") #define TXT_CENTER dxx_gettext(141, "center") #define TXT_CONTROL_KEYBOARD dxx_gettext(142, "Keyboard only") #define TXT_CONTROL_JOYSTICK dxx_gettext(143, "Joystick") #define TXT_CONTROL_FSTICKPRO dxx_gettext(144, "CH Flightstick Pro") #define TXT_CONTROL_THRUSTFCS dxx_gettext(145, "Thrustmaster FCS &\nWingman Extreme") #define TXT_CONTROL_GGAMEPAD dxx_gettext(146, "Gravis Gamepad") #define TXT_CONTROL_MOUSE dxx_gettext(147, "Mouse") #define TXT_CONTROL_CYBERMAN dxx_gettext(148, "Cyberman") #define TXT_CUST_ABOVE dxx_gettext(149, "Customize Above") #define TXT_CUST_KEYBOARD dxx_gettext(150, "Customize Keyboard") #define TXT_CONTROLS dxx_gettext(151, "Controls") #define TXT_KEYBOARD dxx_gettext(152, "Keyboard") #define TXT_REGISTRATION dxx_gettext(172, "This copy of Descent is for use by:") #define TXT_ERROR_SELECTOR dxx_gettext(173, "Error initializing selector for segment A000.") #define TXT_ERROR_GRAPHICS dxx_gettext(174, "Error trying to initialize unsupported graphics mode.") #define TXT_CALIBRATE dxx_gettext(175, "Calibrate") #define TXT_SKIP dxx_gettext(176, "Skip") #define TXT_JOYSTICK_NOT_CEN dxx_gettext(177, "It looks like your joystick\nisn't centered. Do you want\nto calibrate it?") #define TXT_CHOOSE_INPUT dxx_gettext(178, "Choose input device") #define TXT_ERROR dxx_gettext(179, "Error") #define TXT_ERROR_PLR_VERSION dxx_gettext(180, "Cannot open player file\nVersion mismatch.") #define TXT_DEMO_PLAYBACK dxx_gettext(181, "Demo Playback") #define TXT_DEMO_RECORDING dxx_gettext(182, "Demo Recording") #define TXT_CRUISE dxx_gettext(183, "Cruise:") #define TXT_DUMPING_SCREEN dxx_gettext(184, "Dumping screen to") #define TXT_CHEATS_ENABLED dxx_gettext(185, "Cheats Enabled!!") #define TXT_NET_GAME_CLOSED dxx_gettext(186, "That game is closed to new players.") #define TXT_NET_GAME_FULL dxx_gettext(187, "The game is already full.") #define TXT_NET_GAME_BETWEEN dxx_gettext(188, "The game is between levels.\nTry again later.") #define TXT_NET_GAME_NSELECT dxx_gettext(189, "You were not selected for the game.") #define TXT_NET_GAME_NSTART dxx_gettext(190, "The netgame was not started.") #define TXT_NET_GAME_CONNECT dxx_gettext(191, "You are already connected.\nTry again in a minute.") #define TXT_NET_GAME_WRONGLEV dxx_gettext(192, "Wrong level selected.\nPlease re-join.") #define TXT_KILLS dxx_gettext(193, "kills") #define TXT_WAITING dxx_gettext(194, "Waiting for other players..\n") #define TXT_SURE_LEAVE_GAME dxx_gettext(195, "Are you sure you want\nto leave the game?") #define TXT_JOINING dxx_gettext(196, "is joining the game.") #define TXT_REJOIN dxx_gettext(197, "is rejoining the game") #define TXT_SORRY_ONLY dxx_gettext(198, "Sorry, but a you can only select\nup to") #define TXT_NETPLAYERS_IN dxx_gettext(199, "netplayers for this mine.") #define TXT_S_GAME dxx_gettext(200, "'s game") #define TXT_DESCRIPTION dxx_gettext(201, "Description:") #define TXT_LEVEL_ dxx_gettext(202, "Level:") #define TXT_MODE dxx_gettext(203, "Mode:") #define TXT_ANARCHY dxx_gettext(204, "Anarchy") #define TXT_TEAM_ANARCHY dxx_gettext(205, "Team Anarchy") #define TXT_ANARCHY_W_ROBOTS dxx_gettext(206, "Robo-Anarchy") #define TXT_COOPERATIVE dxx_gettext(207, "Cooperative") #define TXT_OPTIONS dxx_gettext(208, "Options:") #define TXT_CLOSED_GAME dxx_gettext(209, "Closed Game") #define TXT_NETGAME_SETUP dxx_gettext(210, "Game Setup") #define TXT_LEVEL_OUT_RANGE dxx_gettext(211, "That start level is out of range") #define TXT_SORRY dxx_gettext(212, "Sorry") #define TXT_REGISTERED_ONLY dxx_gettext(213, "That game mode is\nonly available in\nthe registered/commercial\nversion") #define TXT_WAIT dxx_gettext(214, "Wait...") #define TXT_FOUND dxx_gettext(215, "Found") #define TXT_ACTIVE_GAMES dxx_gettext(216, "active games.") #define TXT_STARTING_NETGAME dxx_gettext(217, "Starting netgame on level") #define TXT_NETLEVEL_NMATCH dxx_gettext(218, "Your level file does not\nmatch the other player's.\nCannot join game.") #define TXT_TEAM dxx_gettext(219, "Team") #define TXT_TEAM_SELECTION dxx_gettext(220, "Team selection\nSelect names to switch teams") #define TXT_TEAM_MUST_ONE dxx_gettext(221, "You must place at least\none player on each team.") #define TXT_TEAM_SELECT dxx_gettext(222, "Select up to") #define TXT_TEAM_PRESS_ENTER dxx_gettext(223, "players\nPress ENTER to begin.") #define TXT_TEAM_ATLEAST_TWO dxx_gettext(224, "You must select at least two\nplayers to start a network game") #define TXT_IPX_NOT_FOUND dxx_gettext(225, "An active IPX driver was\nnot found. Check your\nnetwork software") #define TXT_NET_FORMING dxx_gettext(226, " FORMING, level:") #define TXT_NET_PLAYERS dxx_gettext(227, "players:") #define TXT_NET_JOIN dxx_gettext(228, " OPEN, level:") #define TXT_NET_CLOSED dxx_gettext(229, " CLOSED") #define TXT_NET_BETWEEN dxx_gettext(230, " BETWEEN LEVELS") #define TXT_NET_LEAVE dxx_gettext(231, "\nESC to leave netgame") #define TXT_NET_WAITING dxx_gettext(232, "Waiting for signal from") #define TXT_NET_TO_ENTER dxx_gettext(233, "to enter the mine") #define TXT_NET_SEARCHING dxx_gettext(234, "Searching for Netgames...") #define TXT_INVALID_CHOICE dxx_gettext(235, "That choice is invalid.\n") #define TXT_NET_GAME_BETWEEN2 dxx_gettext(236, "That game is between levels.\nWait for status to change\nand try joining again.") #define TXT_VERSION_MISMATCH dxx_gettext(237, "Your version of Descent\ndoes not match the version\nin use for that game.") #define TXT_GAME_FULL dxx_gettext(238, "That game is currently full.") #define TXT_IN_PROGRESS dxx_gettext(239, "You cannot join that\ngame in progress.") #define TXT_DISCONNECTING dxx_gettext(240, "has disconnected!") #define TXT_SERIAL_OPEN_ERROR dxx_gettext(241, "Error opening serial driver.\nCheck your serial parameters\nAnd free conventional memory.") #define TXT_CARRIER_LOST dxx_gettext(242, "Error!\nCarrier Lost.\n Leaving Multiplayer game.") #define TXT_ERROR_SERIAL_CFG dxx_gettext(243, "Error writing to the file\nserial.cfg. Can't save settings.") #define TXT_ERR_SER_SETTINGS dxx_gettext(244, "Error reading serial settings.\nUsing defaults.") #define TXT_CONNECT_LOST dxx_gettext(245, "No message received from\n%s for 10 seconds.\nConnection may be lost.") #define TXT_READY_DESCENT dxx_gettext(246, "Your opponent has selected\nstart game. Are you\nready for descent?") #define TXT_CLOSED_LINK dxx_gettext(247, "Your opponent has disconnected.") #define TXT_DIAL_MODEM dxx_gettext(248, "Dial modem...") #define TXT_ANSWER_MODEM dxx_gettext(249, "Answer modem") #define TXT_NULL_MODEM dxx_gettext(250, "Establish null-modem link") #define TXT_COM_SETTINGS dxx_gettext(251, "COM settings...") #define TXT_START_GAME dxx_gettext(252, "Start game...") #define TXT_SEND_MESSAGEP dxx_gettext(253, "Send message...") #define TXT_HANGUP_MODEM dxx_gettext(254, "Hang up modem") #define TXT_CLOSE_LINK dxx_gettext(255, "Close link") #define TXT_SERIAL dxx_gettext(256, "Serial") #define TXT_LINK_ACTIVE dxx_gettext(257, "link active to") #define TXT_MODEM dxx_gettext(258, "Modem") #define TXT_NOT_CONNECTED dxx_gettext(259, "Not currently connected") #define TXT_SERIAL_GAME dxx_gettext(260, "Serial Game") #define TXT_EXIT_WILL_CLOSE dxx_gettext(261, "Exiting this menu\nwill close the link\nContinue?") #define TXT_BAUD_RATE dxx_gettext(262, "Baud Rate:") #define TXT_MODEM_INIT_STRING dxx_gettext(263, "Modem Init String:") #define TXT_ACCEPT_SAVE dxx_gettext(264, "Accept and Save") #define TXT_SERIAL_SETTINGS dxx_gettext(265, "Serial Settings") #define TXT_WARNING_16550 dxx_gettext(266, "Warning!\nYou must have a\n16550 UART\nto use 38400") #define TXT_DIFFICULTY dxx_gettext(267, "Difficulty:") #define TXT_SERIAL_GAME_SETUP dxx_gettext(268, "Serial Game Setup") #define TXT_ONLY_ANARCHY dxx_gettext(269, "Only Anarchy mode is\navailable in the\nshareware version.") #define TXT_SAVE dxx_gettext(270, "Save!") #define TXT_ACCEPT dxx_gettext(271, "Accept") #define TXT_SEL_NUMBER_EDIT dxx_gettext(272, "Select a number to edit") #define TXT_EDIT_PHONE_ENTRY dxx_gettext(273, "Edit phonebook entry") #define TXT_MANUAL_ENTRY dxx_gettext(274, "Manual Entry") #define TXT_EDIT_PHONEBOOK dxx_gettext(275, "Edit Phonebook") #define TXT_SEL_NUMBER_DIAL dxx_gettext(276, "Select a number to dial") #define TXT_ENTER_NUMBER_DIAL dxx_gettext(277, "Enter number to dial") #define TXT_NO_DIAL_TONE dxx_gettext(278, "NO DIAL TONE") #define TXT_BUSY dxx_gettext(279, "BUSY") #define TXT_NO_ANSWER dxx_gettext(280, "NO ANSWER") #define TXT_NO_CARRIER dxx_gettext(281, "NO CARRIER") #define TXT_VOICE dxx_gettext(282, "VOICE") #define TXT_ERR_MODEM_RETURN dxx_gettext(283, "Error!\nModem returned:") #define TXT_CONNECT dxx_gettext(284, "CONNECT") #define TXT_BAUD_GREATER_9600 dxx_gettext(285, "Error!\nYou must establish a\n9600 baud connection\nor higher to play.") #define TXT_RING dxx_gettext(286, "RING") #define TXT_NO_SERIAL_OPT dxx_gettext(287, "Descent was started with\nthe serial option disabled.") #define TXT_RESET_MODEM dxx_gettext(288, "Resetting Modem") #define TXT_NO_MODEM dxx_gettext(289, "No modem detected.\nCheck your com settings.") #define TXT_NO_PHONENUM dxx_gettext(290, "That phone number\nis not defined.\n") #define TXT_DIALING dxx_gettext(291, "Dialing:") #define TXT_ESC_ABORT dxx_gettext(292, "ESC to abort") #define TXT_WAITING_FOR_ANS dxx_gettext(293, "Waiting for answer...") #define TXT_WAITING_FOR_CALL dxx_gettext(294, "Waiting for call...") #define TXT_WAITING_FOR_CARR dxx_gettext(295, "Waiting for carrier...") #define TXT_FAILED_TO_NEGOT dxx_gettext(296, "Failed to negotiate!") #define TXT_NEGOTIATION_FAIL dxx_gettext(297, "Negotiation with remote player\nfailed. Cannot continue.") #define TXT_FATAL_ERROR_LEVEL dxx_gettext(298, "Fatal error.\nMy level =") #define TXT_OTHER_LEVEL dxx_gettext(299, "Other level =") #define TXT_YOUR_LEVEL dxx_gettext(300, "Your level ") #define TXT_LVL_NO_MATCH dxx_gettext(301, "file does\nnot match") #define TXT_CHECK_VERSION dxx_gettext(302, "'s.\nCheck your versions.") #define TXT_DESCENT_NO_MATCH dxx_gettext(303, "Your version of Descent\ndoes not match that of\nyour opponent.") #define TXT_OPPONENT_NO_READY dxx_gettext(304, "Your opponent is not\nready to start the game.") #define TXT_WAIT_OPPONENT dxx_gettext(305, "Waiting for remote player...") #define TXT_LOCK dxx_gettext(306, "LOCK") #define TXT_DEATHS dxx_gettext(307, "DEATHS") #define TXT_LIVES dxx_gettext(308, "LIVES") #define TXT_LVL dxx_gettext(309, "LVL") #define TXT_QUAD dxx_gettext(310, "QUAD") #define TXT_REAR_VIEW dxx_gettext(311, "REAR VIEW") #define TXT_DIFFICULTY_1 dxx_gettext(312, "Trainee") #define TXT_DIFFICULTY_2 dxx_gettext(313, "Rookie") #define TXT_DIFFICULTY_3 dxx_gettext(314, "Hotshot") #define TXT_DIFFICULTY_4 dxx_gettext(315, "Ace") #define TXT_DIFFICULTY_5 dxx_gettext(316, "Insane") #define TXT_DETAIL_1 dxx_gettext(317, "Lowest") #define TXT_DETAIL_2 dxx_gettext(318, "Low") #define TXT_DETAIL_3 dxx_gettext(319, "Medium") #define TXT_DETAIL_4 dxx_gettext(320, "High") #define TXT_DETAIL_5 dxx_gettext(321, "Highest") #define TXT_DETAIL_CUSTOM_ dxx_gettext(322, "Custom...") #define TXT_LOAD_GAME dxx_gettext(323, "Load Game...") #define TXT_MULTIPLAYER_ dxx_gettext(324, "Multiplayer...") #define TXT_OPTIONS_ dxx_gettext(325, "Options...") #define TXT_CHANGE_PILOTS dxx_gettext(326, "Change Pilots...") #define TXT_VIEW_DEMO dxx_gettext(327, "View Demo...") #define TXT_CREDITS dxx_gettext(328, "Credits") #define TXT_ORDERING_INFO dxx_gettext(329, "Ordering Info") #define TXT_SELECT_DEMO dxx_gettext(330, "Select Demo\n deletes\n converts format\nIntel <-> PowerPC") #define TXT_DIFFICULTY_LEVEL dxx_gettext(331, "Difficulty Level") #define TXT_SET_TO dxx_gettext(332, "set to") #define TXT_DETAIL_LEVEL dxx_gettext(333, "Detail Level") #define TXT_OBJ_COMPLEXITY dxx_gettext(334, "Object Complexity") #define TXT_OBJ_DETAIL dxx_gettext(335, "Object Detail") #define TXT_WALL_DETAIL dxx_gettext(336, "Wall Detail") #define TXT_WALL_RENDER_DEPTH dxx_gettext(337, "Wall Render Depth") #define TXT_DEBRIS_AMOUNT dxx_gettext(338, "Amount of Debris") #define TXT_SOUND_CHANNELS dxx_gettext(339, "Sound Channels") #define TXT_LO_HI dxx_gettext(340, " LO HI") #define TXT_DETAIL_CUSTOM dxx_gettext(341, "Detail Level Customization") #define TXT_START_ANY_LEVEL dxx_gettext(342, "You may start on\nany level up to") #define TXT_SELECT_START_LEV dxx_gettext(343, "New Game\n\nSelect starting level") #define TXT_ENTER_TO_CONT dxx_gettext(344, "Press ENTER to Continue") #define TXT_INVALID_LEVEL dxx_gettext(345, "Invalid level number") #define TXT_ERR_LOADING_GAME dxx_gettext(346, "Error Loading Game") #define TXT_SAVE_GAME_SLOTS dxx_gettext(347, "Save Game\n\nSelect slot & enter save name\nPress ESC if you don't want to save") #define TXT_SAVE_ERROR dxx_gettext(348, "Save Error!") #define TXT_FX_VOLUME dxx_gettext(349, "FX Volume") #define TXT_MUSIC_VOLUME dxx_gettext(350, "Music Volume") #define TXT_REVERSE_STEREO dxx_gettext(351, "Reverse Stereo") #define TXT_BRIGHTNESS dxx_gettext(352, "Brightness") #define TXT_CONTROLS_ dxx_gettext(353, "Controls...") #define TXT_DETAIL_LEVELS dxx_gettext(354, "Detail levels...") #define TXT_CAL_JOYSTICK dxx_gettext(355, "Calibrate Joystick") #define TXT_JOYS_SENSITIVITY dxx_gettext(356, "Joystick/Mouse\nSensitivity") #define TXT_START_NET_GAME dxx_gettext(357, "Start a network game...") #define TXT_JOIN_NET_GAME dxx_gettext(358, "Join a network game...\n") #define TXT_MODEM_GAME dxx_gettext(359, "Modem/serial game...") #define TXT_MULTIPLAYER dxx_gettext(360, "Multiplayer") #define TXT_CONTINUE dxx_gettext(361, "Continue") #define TXT_CANT_PLAYBACK dxx_gettext(362, "Can't playback demo") #define TXT_DEMO_CORRUPT dxx_gettext(363, "because\ndemo file contains corrupt\ndata.") #define TXT_DEMO_OLD dxx_gettext(364, "because\ndemo version is too old.") #define TXT_RECORDED dxx_gettext(365, "recorded") #define TXT_WITH_REGISTERED dxx_gettext(366, "with the registered version") #define TXT_WITH_SHAREWARE dxx_gettext(367, "with the shareware version") #define TXT_OF_DESCENT dxx_gettext(368, "of Descent.") #define TXT_LEVEL_CANT_LOAD dxx_gettext(369, "because\nlevel cannot be loaded.") #define TXT_DEMO_OLD_CORRUPT dxx_gettext(370, "Demo is probably too old\nor contains corrupt data.") #define TXT_DEMO_ERR_READING dxx_gettext(371, "Error reading demo data.") #define TXT_SAVE_DEMO_AS dxx_gettext(372, "Save Demo as:") #define TXT_DEMO_USE_LETTERS dxx_gettext(373, "Please use only letters,\nnumbers and the underscore\ncharacter in filename.") #define TXT_AUTOMAP dxx_gettext(374, "Automap") #define TXT_TURN_SHIP dxx_gettext(375, "Flight controls move") #define TXT_SLIDE_UPDOWN dxx_gettext(376, "Accelerate/Reverse zooms in/out") #define TXT_LEVEL dxx_gettext(377, "Level") #define TXT_PITCH_FORWARD dxx_gettext(378, "Pitch forward") #define TXT_PITCH_BACKWARD dxx_gettext(379, "Pitch backward") #define TXT_TURN_LEFT dxx_gettext(380, "Turn left") #define TXT_TURN_RIGHT dxx_gettext(381, "Turn right") #define TXT_SLIDE_ON dxx_gettext(382, "Slide on") #define TXT_SLIDE_LEFT dxx_gettext(383, "Slide left") #define TXT_SLIDE_RIGHT dxx_gettext(384, "Slide right") #define TXT_SLIDE_UP dxx_gettext(385, "Slide up") #define TXT_SLIDE_DOWN dxx_gettext(386, "Slide down") #define TXT_BANK_ON dxx_gettext(387, "Bank on") #define TXT_BANK_LEFT dxx_gettext(388, "Bank left") #define TXT_BANK_RIGHT dxx_gettext(389, "Bank right") #define TXT_FIRE_PRIMARY dxx_gettext(390, "Fire primary") #define TXT_FIRE_SECONDARY dxx_gettext(391, "Fire secondary") #define TXT_FIRE_FLARE dxx_gettext(392, "Fire flare") #define TXT_ACCELERATE dxx_gettext(393, "Accelerate") #define TXT_REVERSE dxx_gettext(394, "reverse") #define TXT_DROP_BOMB dxx_gettext(395, "Drop Bomb") #define TXT_CRUISE_FASTER dxx_gettext(396, "Cruise Faster") #define TXT_CRUISE_SLOWER dxx_gettext(397, "Cruise Slower") #define TXT_CRUISE_OFF dxx_gettext(398, "Cruise Off") #define TXT_PITCH_UD dxx_gettext(399, "Pitch U/D") #define TXT_TURN_LR dxx_gettext(400, "Turn L/R") #define TXT_SLIDE_LR dxx_gettext(401, "Slide L/R") #define TXT_SLIDE_UD dxx_gettext(402, "Slide U/D") #define TXT_BANK_LR dxx_gettext(403, "Bank L/R") #define TXT_THROTTLE dxx_gettext(404, "throttle") #define TXT_TEAM_ATLEAST_THREE dxx_gettext(405, "You must select at least three\nplayers to start a team game") #define TXT_NET_DISCONNECTED dxx_gettext(406, "Disconnected") #define TXT_NET_PLAYING dxx_gettext(407, "Playing") #define TXT_NET_ESCAPED dxx_gettext(408, "Escaped") #define TXT_NET_DIED dxx_gettext(409, "Died in mine") #define TXT_NET_FOUND_SECRET dxx_gettext(410, "Found secret level") #define TXT_NET_ESCAPE_TUNNEL dxx_gettext(411, "In Escape tunnel") #define TXT_NET_RESERVED dxx_gettext(412, "Viewing Level Scores") #define TXT_WOWIE_ZOWIE dxx_gettext(413, "Wowie Zowie Weapons!!") #define TXT_ALL_KEYS dxx_gettext(414, "All Keys!") #define TXT_CLOAK dxx_gettext(415, "Cloak") #define TXT_FULL_SHIELDS dxx_gettext(416, "Shields Recharged!") #define TXT_ON dxx_gettext(417, "On") #define TXT_OFF dxx_gettext(418, "Off") #define TXT_NOT_IN_SHAREWARE dxx_gettext(419, "Not available in shareware") #define TXT_GAME_OVER dxx_gettext(420, "Game Over") #define TXT_SELECT_PILOT dxx_gettext(421, "Select pilot\n deletes") #define TXT_ENTER_PILOT_NAME dxx_gettext(422, "Enter your pilot name:") #define TXT_PLAYER dxx_gettext(423, "Player") #define TXT_ALREADY_EXISTS dxx_gettext(424, "already exists!") #define TXT_LOADING dxx_gettext(425, "Prepare for Descent...") #define TXT_FULL_RESCUE_BONUS dxx_gettext(426, "Full Rescue bonus: \t") #define TXT_SHIELD_BONUS dxx_gettext(427, "Shield bonus:\t") #define TXT_ENERGY_BONUS dxx_gettext(428, "Energy bonus:\t") #define TXT_HOSTAGE_BONUS dxx_gettext(429, "Hostage bonus: \t") #define TXT_SKILL_BONUS dxx_gettext(430, "Skill Bonus:\t") #define TXT_TOTAL_BONUS dxx_gettext(431, "Total Bonus:\t") #define TXT_TOTAL_SCORE dxx_gettext(432, "Total Score:\t") #define TXT_SECRET_LEVEL dxx_gettext(433, "Secret Level") #define TXT_COMPLETE dxx_gettext(434, "Complete") #define TXT_DESTROYED dxx_gettext(435, "Destroyed!") #define TXT_SAVE_GAME dxx_gettext(436, "Save Game?") #define TXT_PRESS_CTRL_R dxx_gettext(437, "Press to reset") #define TXT_RESET_HIGH_SCORES dxx_gettext(438, "Reset the high scores?") #define TXT_YOU_WERE dxx_gettext(439, "You were") #define TXT_WAS dxx_gettext(440, "was") #define TXT_KILLED_BY_NONPLAY dxx_gettext(441, "killed by the reactor") #define TXT_IMPORTANT_NOTE dxx_gettext(442, "IMPORTANT NOTE") #define TXT_FCS dxx_gettext(443, "Use this option for the FCS\nand Wingman Extreme only\nwhen used alone. If you\nalso use a WCS or FLCS you\nmust configure for joystick.\nSee manual/readme for details.\n") #define TXT_PRESS_ANY_KEY dxx_gettext(444, "Press any key or button to continue...") #define TXT_HOSTAGE_RESCUED dxx_gettext(445, "Hostage rescued!") #define TXT_INIT_VICTOR dxx_gettext(446, "Initializing VictorMaxx tracking on COM port") #define TXT_N dxx_gettext(447, "N") #define TXT_Y dxx_gettext(448, "Y") #define TXT_ANY_LEVEL dxx_gettext(449, "Start at any level.") #define TXT_SHAREWARE_DONE dxx_gettext(450, "Shareware Levels Completed") #define TXT_PRESS_NEW_KEY dxx_gettext(451, "Press new key") #define TXT_PRESS_NEW_JBUTTON dxx_gettext(452, "Press new joystick button") #define TXT_PRESS_NEW_MBUTTON dxx_gettext(453, "Press new mouse button") #define TXT_MOVE_NEW_JOY_AXIS dxx_gettext(454, "Move new joystick axis") #define TXT_MOVE_NEW_MSE_AXIS dxx_gettext(455, "Move new mouse axis") #define TXT_USING_VFX1 dxx_gettext(456, "Using VFX1 Head Tracking...Press Shift+Z during game to set zero.") #define TXT_VFX1_ERROR1 dxx_gettext(457, "Error: Can't use VFX1 head tracking because no head tracking device\nwas found.") #define TXT_VFX1_ERROR2 dxx_gettext(458, "Error: Can't use VFX1 head tracking because VFX1.COM does not\nappear to be loaded!") #define TXT_KCONFIG_STRING_1 dxx_gettext(459, "Enter changes, ^D deletes, ^R resets defaults, Esc exits") #define TXT_BUTTONS dxx_gettext(460, " Buttons ") #define TXT_AXES dxx_gettext(461, " Axes ") #define TXT_AXIS dxx_gettext(462, "Axis") #define TXT_INVERT dxx_gettext(463, "Invert?") #define TXT_BTN_1 dxx_gettext(464, "BTN 1") #define TXT_BTN_2 dxx_gettext(465, "BTN 2") #define TXT_BTN_3 dxx_gettext(466, "BTN 3") #define TXT_BTN_4 dxx_gettext(467, "BTN 4") #define TXT_TRIG dxx_gettext(468, "TRIG") #define TXT_HAT_L dxx_gettext(469, "HAT \x81") #define TXT_HAT_R dxx_gettext(470, "HAT \x80") #define TXT_HAT_U dxx_gettext(471, "HAT \x7f") #define TXT_HAT_D dxx_gettext(472, "HAT \x82") #define TXT_LEFT dxx_gettext(473, "LEFT") #define TXT_RIGHT dxx_gettext(474, "RIGHT") #define TXT_MID dxx_gettext(475, "MID") #define TXT_UP dxx_gettext(476, "UP") #define TXT_DOWN dxx_gettext(477, "DOWN") #define TXT_X1 dxx_gettext(478, "X1") #define TXT_Y1 dxx_gettext(479, "Y1") #define TXT_X2 dxx_gettext(480, "X2") #define TXT_Y2 dxx_gettext(481, "Y2") #define TXT_L_R dxx_gettext(482, "L/R") #define TXT_F_B dxx_gettext(483, "F/B") #define TXT_FORWARD dxx_gettext(484, "forward") #define TXT_MOVE_THROTTLE_F dxx_gettext(485, "Move throttle all\nthe way forward\nand press any button") #define TXT_MOVE_THROTTLE_R dxx_gettext(486, "Move throttle all\nthe way back\nand press any button") #define TXT_MOVE_THROTTLE_C dxx_gettext(487, "Move throttle to\nits center and\npress any button") #define TXT_REACTOR_EXPLODED dxx_gettext(488, "\nReactor has exploded.") #define TXT_TIME_REMAINING dxx_gettext(489, "\nTime Remaining") #define TXT_SECONDS dxx_gettext(490, "seconds.") #define TXT_DEMO_WRITE_ERROR dxx_gettext(491, "Error writing demo file. Current") #define TXT_DEMO_SIZE dxx_gettext(492, "demo size is") #define TXT_DEMO_SAVE_BAD dxx_gettext(493, "You are nearly out of space on\nthe current device. Enter demo\nname now or press ESC to delete\ndemo.") #define TXT_BYTE_STR dxx_gettext(494, "bytes.") #define TXT_DIED_IN_MINE dxx_gettext(495, "You died in the mine.\n\nYour ship and its contents\nwere incinerated.") #define TXT_SHIP_BONUS dxx_gettext(496, "Ship bonus: \t") #define TXT_PHONE_NUM dxx_gettext(497, "Phone Number") #define TXT_KILL_MATRIX_TITLE dxx_gettext(498, "ANARCHY SUMMARY") #define TXT_WAIT_FOR_OK dxx_gettext(499, "Waiting for OK to\nstart game\n") #define TXT_SURE_ABORT_SYNC dxx_gettext(500, "Aborting will quit the game\nare you sure?") #define TXT_ERROR_WRITING_PLR dxx_gettext(501, "Error writing player file.\nUnable to save current player.\n") #define TXT_SHIP_DESTROYED_0 dxx_gettext(502, "Ship destroyed!") #define TXT_SHIP_DESTROYED_1 dxx_gettext(503, "Ship destroyed, 1 hostage lost!") #define TXT_SHIP_DESTROYED_2 dxx_gettext(504, "Ship destroyed, %i hostages lost!") #define TXT_NET_FULL dxx_gettext(505, "This socket is ready full.\nPlease restart Descent\nwith the -socket option.\n\nfor example: Descent -socket 1") #define TXT_DEMO_NO_SPACE dxx_gettext(506, "Not enough space on current\ndevice to start demo recording.") #define TXT_HAT2_L dxx_gettext(507, "HAT2\x81") #define TXT_HAT2_R dxx_gettext(508, "HAT2\x7f") #define TXT_HAT2_U dxx_gettext(509, "HAT2\x82") #define TXT_HAT2_D dxx_gettext(510, "HAT2\x80") #define TXT_WARP_TO_LEVEL dxx_gettext(511, "Warp to which level?") #define TXT_TRADEMARK dxx_gettext(512, "DESCENT is a trademark of Interplay Productions, Inc.") #define TXT_NET_SYNC_FAILED dxx_gettext(513, "Failed to join the netgame.\nYou are missing packets. Check\nyour network card and\ntry again.") #define TXT_DONE dxx_gettext(514, "done") #define TXT_I_AM_A dxx_gettext(515, "I am a") #define TXT_CHEATER dxx_gettext(516, "CHEATER!") #define TXT_LOADING_DATA dxx_gettext(517, "Loading Data") #define TXT_HELP_ALT_F2 dxx_gettext(518, "ALT-F2\t Save Game") #define TXT_HELP_ALT_F3 dxx_gettext(519, "ALT-F3\t Load Game") #define TXT_ONLY_REGISTERED dxx_gettext(520, "Only in Registered version!") #define TXT_CONCUSSION dxx_gettext(521, "Concussion") #define TXT_HOMING dxx_gettext(522, "Homing") #define TXT_PROXBOMB dxx_gettext(523, "ProxBomb") #define TXT_SMART dxx_gettext(524, "Smart") #define TXT_MEGA dxx_gettext(525, "Mega") #define TXT_NOMISSION4DEMO dxx_gettext(526, "Mission '%s' not found.\nYou must have this mission\nfile in order to playback\nthis demo.") #define TXT_SHOW_IDS dxx_gettext(527, "All player callsigns on screen") #define TXT_DUPLICATE_NAME dxx_gettext(528, "There is already a game\nin progress with that name") #define TXT_ANARCHY_ONLY_MISSION dxx_gettext(529, "This mission is designated\nAnarchy-only") #define TXT_START_NOWAIT dxx_gettext(530, "Force level start") #define TXT_QUITTING_NOW dxx_gettext(531, "Quitting now means ending the\nentire netgame\n\nAre you sure?") #define TXT_MISSION_NOT_FOUND dxx_gettext(532, "The mission for that netgame\nis not installed on your\nsystem. Cannot join.") #define TXT_MULTI_MISSION dxx_gettext(533, "Start Multiplayer Game\n\nSelect mission") #define TXT_MISSION_ERROR dxx_gettext(534, "Error loading mission file") #define TXT_COM_CUSTOM_SETTINGS dxx_gettext(535, "Custom (return to set)") #define TXT_COM_BASE dxx_gettext(536, "Base address (in Hex)") #define TXT_COM_IRQ dxx_gettext(537, "IRQ Number") #define TXT_RESET_DEFAULTS dxx_gettext(538, "Reset to Default") #define TXT_VALID_IRQS dxx_gettext(539, "Valid IRQ values are 2-7") #define TXT_NO_UART dxx_gettext(540, "No UART was detected\nat those settings") #define TXT_DEF_MACRO_1 dxx_gettext(541, "You will pay dearly for that!") #define TXT_DEF_MACRO_2 dxx_gettext(542, "Revenge is mine!!") #define TXT_DEF_MACRO_3 dxx_gettext(543, "Man I'm good!") #define TXT_DEF_MACRO_4 dxx_gettext(544, "Its almost too easy!") #define TXT_MISSION dxx_gettext(545, " Mission:") #define TXT_VIEWING_DISTANCE dxx_gettext(546, "+/- Changes viewing distance") #define TXT_SECRET_EXIT dxx_gettext(547, "Alternate exit found!\n\nProceeding to Secret Level!") #define TXT_SHOW_ON_MAP dxx_gettext(548, "Show all players on automap") #define TXT_KILLED_BY_ROBOT dxx_gettext(549, "Killed by a robot") #define TXT_BAUD dxx_gettext(550, "Baud") #define TXT_CONSISTENCY_ERROR dxx_gettext(551, "A consistency error has been\ndetected in your network connection.\nCheck you hardware and re-join") #define TXT_PRESS_ANY_KEY2 dxx_gettext(552, "Press any key to continue (Print Screen to save screenshot)") #define TXT_DEMO_SAVE_NOSPACE dxx_gettext(553, "An error occured while writing\ndemo. Demo is likely corrupted.\nEnter demo name now or\npress ESC to delete demo.") #define TXT_CNTRLCEN_INVUL dxx_gettext(554, "The main reactor is invulnerable for") #define TXT_NO_DESTSAT_LVL dxx_gettext(555, "The level being loaded is not\navailable in Destination Saturn.\nUnable to continue demo playback.\n\nPress any key to continue.") #define TXT_REACTOR_LIFE dxx_gettext(556, "Reactor life") #define TXT_MINUTES_ABBREV dxx_gettext(557, "min") #define TXT_CURRENT_IPX_SOCKET dxx_gettext(558, "Current IPX Socket is default") #define TXT_DOS_VERSION_1 dxx_gettext(559, "This program requires MS-DOS 5.0 or higher.\nYou are using MS-DOS") #define TXT_DOS_VERSION_2 dxx_gettext(560, "You can use the -nodoscheck command line\nswitch to override this check, but it\nmay have unpredictable results, namely\nwith DOS file error handling.\n") #define TXT_NOT_ENOUGH_HANDLES dxx_gettext(561, "Not enough file handles!") #define TXT_HANDLES_1 dxx_gettext(562, "of the necessary file handles\nthat Descent requires to execute properly. You will\nneed to increase the FILES=n line in your config.sys.") #define TXT_HANDLES_2 dxx_gettext(563, "If you are running with a clean boot, then you will need\nto create a CONFIG.SYS file in your root directory, with\nthe line FILES=15 in it. If you need help with this,\ncontact Interplay technical support.") #define TXT_HANDLES_3 dxx_gettext(564, "You may also run with the -nofilecheck command line option\nthat will disable this check, but you might get errors\nwhen loading saved games or playing demos.") #define TXT_AVAILABLE_MEMORY dxx_gettext(565, "Available memory") #define TXT_MEMORY_CONFIG dxx_gettext(566, "more bytes of DOS memory needed!") #define TXT_RECONFIGURE_VMM dxx_gettext(567, "more bytes of virtual memory needed. Reconfigure VMM.") #define TXT_MORE_MEMORY dxx_gettext(568, "more bytes of extended/expanded memory needed!") #define TXT_MORE_MEMORY_2 dxx_gettext(569, "Or else you you need to use virtual memory (See README.TXT)") #define TXT_PHYSICAL_MEMORY dxx_gettext(570, "more bytes of physical memory needed!") #define TXT_PHYSICAL_MEMORY_2 dxx_gettext(571, "Check to see that your virtual memory settings allow\nyou to use all of your physical memory (See README.TXT)") #define TXT_INITIALIZING_DPMI dxx_gettext(572, "Initializing DPMI services") #define TXT_INITIALIZING_CRIT dxx_gettext(573, "Initializing critical error handler") #define TXT_IGLASSES dxx_gettext(574, "Enables Virtual I/O Iglasses! stereo display") #define TXT_VIOTRACK dxx_gettext(575, "Enables Iglasses! head tracking via COM port") #define TXT_KASAN dxx_gettext(576, "Enables Kasan's 3dMax stereo display in low res.") #define TXT_KASAN_2 dxx_gettext(577, "3DBios must be installed for 3dMax operation.") #define TXT_3DMAX dxx_gettext(578, "Enables Kasan's 3dMax stereo display in high res") #define TXT_PRESS_ANY_KEY3 dxx_gettext(579, "Press any key for more options...") #define TXT_SOCKET dxx_gettext(580, "Enables dynamic socket changing") #define TXT_NOFILECHECK dxx_gettext(581, "Disables the file handles check") #define TXT_VERBOSE_1 dxx_gettext(582, "Getting settings from DESCENT.CFG...") #define TXT_VERBOSE_2 dxx_gettext(583, "Initializing timer system...") #define TXT_VERBOSE_3 dxx_gettext(584, "Initializing keyboard handler...") #define TXT_VERBOSE_4 dxx_gettext(585, "Initializing mouse handler...") #define TXT_VERBOSE_5 dxx_gettext(586, "Mouse support disabled...") #define TXT_VERBOSE_6 dxx_gettext(587, "Initializing joystick handler...") #define TXT_VERBOSE_7 dxx_gettext(588, "Slow joystick reading enabled...") #define TXT_VERBOSE_8 dxx_gettext(589, "Polled joystick reading enabled...") #define TXT_VERBOSE_9 dxx_gettext(590, "BIOS joystick reading enabled...") #define TXT_VERBOSE_10 dxx_gettext(591, "Joystick support disabled...") #define TXT_VERBOSE_11 dxx_gettext(592, "Initializing divide by zero handler...") #define TXT_INITIALIZING_NETWORK dxx_gettext(593, "Initializing network...") #define TXT_IPX_CHANNEL dxx_gettext(594, "Using IPX network support on channel") #define TXT_NO_NETWORK dxx_gettext(595, "No IPX compatible network found.") #define TXT_SOCKET_ERROR dxx_gettext(596, "Error opening socket") #define TXT_MEMORY_IPX dxx_gettext(597, "Not enough low memory for IPX buffers.") #define TXT_ERROR_IPX dxx_gettext(598, "Error initializing IPX. Error code:") #define TXT_NETWORK_DISABLED dxx_gettext(599, "Network support disabled...") #define TXT_INITIALIZING_GRAPHICS dxx_gettext(600, "Initializing graphics system...") #define TXT_SOUND_ERROR_OPEN dxx_gettext(601, "SOUND: Error opening") #define TXT_SOUND_ERROR_LOCK dxx_gettext(602, "SOUND: Error locking down instruments") #define TXT_SOUND_ERROR_HMI dxx_gettext(603, "SOUND: (HMI)") #define TXT_SOUND_ERROR_LOCK_DRUMS dxx_gettext(604, "SOUND: Error locking down drums") #define TXT_SOUND_ERROR_MIDI dxx_gettext(605, "SOUND: Error locking midi track map!") #define TXT_SOUND_ERROR_MIDI_CALLBACK dxx_gettext(606, "SOUND: Error locking midi callback function!") #define TXT_EXTERNAL_CONTROL dxx_gettext(607, "Using external control:") #define TXT_IGLASSES_ERROR_1 dxx_gettext(608, "Invalid serial port parameter for -itrak!") #define TXT_IGLASSES_INIT dxx_gettext(609, "Initializing i-glasses! head tracking on serial port %d") #define TXT_IGLASSES_ON dxx_gettext(610, "Make sure the glasses are turned on!") #define TXT_PRESS_ESC_TO_ABORT dxx_gettext(611, "Press ESC to abort") #define TXT_SERIAL_FAILURE dxx_gettext(612, "Failed to open serial port. Status =") #define TXT_MESSAGE dxx_gettext(613, "Message") #define TXT_MACRO dxx_gettext(614, "Macro") #define TXT_ERROR_SERIAL_LOCK dxx_gettext(615, "Error locking serial interrupt routine!") #define TXT_ERROR_SERIAL_LOCK_2 dxx_gettext(616, "Error locking serial port data!") #define TXT_NO_LUNACY dxx_gettext(617, "Robots are normal") #define TXT_LUNACY dxx_gettext(618, "Robots move fast, fire seldom") #define TXT_ROBOT_PAINTING_OFF dxx_gettext(619, "Robot painting OFF") #define TXT_ROBOT_PAINTING_ON dxx_gettext(620, "Robot painting with texture %d") #define N_TEXT_STRINGS_MIN 514 #define N_TEXT_STRINGS 621 #define dxx_text_ensure_simple_expr(E,T) ((void)(E), (Int3()), (T)) #define PRIMARY_WEAPON_NAMES(u) ( \ ((u) == LASER_INDEX) ? TXT_W_LASER : \ ((u) == VULCAN_INDEX) ? TXT_W_VULCAN : \ ((u) == SPREADFIRE_INDEX) ? TXT_W_SPREADFIRE : \ ((u) == PLASMA_INDEX) ? TXT_W_PLASMA : \ ((u) == FUSION_INDEX) ? TXT_W_FUSION : \ (dxx_text_ensure_simple_expr(&(u), TXT_W_LASER)) \ ) #define SECONDARY_WEAPON_NAMES(u) ( \ ((u) == CONCUSSION_INDEX) ? TXT_W_C_MISSILE : \ ((u) == HOMING_INDEX) ? TXT_W_H_MISSILE : \ ((u) == PROXIMITY_INDEX) ? TXT_W_P_BOMB : \ ((u) == SMART_INDEX) ? TXT_W_S_MISSILE : \ ((u) == MEGA_INDEX) ? TXT_W_M_MISSILE : \ (dxx_text_ensure_simple_expr(&(u), TXT_W_C_MISSILE)) \ ) #define PRIMARY_WEAPON_NAMES_SHORT(u) ( \ ((u) == LASER_INDEX) ? TXT_W_LASER_S : \ ((u) == VULCAN_INDEX) ? TXT_W_VULCAN_S : \ ((u) == SPREADFIRE_INDEX) ? TXT_W_SPREADFIRE_S : \ ((u) == PLASMA_INDEX) ? TXT_W_PLASMA_S : \ ((u) == FUSION_INDEX) ? TXT_W_FUSION_S : \ (dxx_text_ensure_simple_expr(&(u), TXT_W_LASER_S)) \ ) #define SECONDARY_WEAPON_NAMES_SHORT(u) ( \ ((u) == CONCUSSION_INDEX) ? TXT_W_C_MISSILE_S : \ ((u) == HOMING_INDEX) ? TXT_W_H_MISSILE_S : \ ((u) == PROXIMITY_INDEX) ? TXT_W_P_BOMB_S : \ ((u) == SMART_INDEX) ? TXT_W_S_MISSILE_S : \ ((u) == MEGA_INDEX) ? TXT_W_M_MISSILE_S : \ (dxx_text_ensure_simple_expr(&(u), TXT_W_C_MISSILE_S)) \ ) #define NET_DUMP_STRINGS(u) ( \ ((u) == DUMP_CLOSED) ? TXT_NET_GAME_CLOSED : \ ((u) == DUMP_FULL) ? TXT_NET_GAME_FULL : \ ((u) == DUMP_ENDLEVEL) ? TXT_NET_GAME_BETWEEN : \ ((u) == DUMP_DORK) ? TXT_NET_GAME_NSELECT : \ ((u) == DUMP_ABORTED) ? TXT_NET_GAME_NSTART : \ ((u) == DUMP_CONNECTED) ? TXT_NET_GAME_CONNECT : \ ((u) == DUMP_LEVEL) ? TXT_NET_GAME_WRONGLEV : \ (dxx_text_ensure_simple_expr(&(u), TXT_NET_GAME_CLOSED)) \ ) #define MENU_DIFFICULTY_TEXT(u) ( \ ((u) == 0) ? TXT_DIFFICULTY_1 : \ ((u) == 1) ? TXT_DIFFICULTY_2 : \ ((u) == 2) ? TXT_DIFFICULTY_3 : \ ((u) == 3) ? TXT_DIFFICULTY_4 : \ ((u) == 4) ? TXT_DIFFICULTY_5 : \ /* &u is ill-formed when u is a literal number */ \ (dxx_text_ensure_simple_expr(NULL, TXT_DIFFICULTY_1)) \ ) #define MENU_DETAIL_TEXT(u) ( \ ((u) == 0) ? TXT_DETAIL_1 : \ ((u) == 1) ? TXT_DETAIL_2 : \ ((u) == 2) ? TXT_DETAIL_3 : \ ((u) == 3) ? TXT_DETAIL_4 : \ ((u) == 4) ? TXT_DETAIL_5 : \ (dxx_text_ensure_simple_expr(&(u), TXT_DETAIL_1)) \ ) void decode_text_line(char *text_line); // decryption for bitmaps.tbl void decode_text(char *text, int len); // decryption for briefings, etc. void load_text(void); void free_text(); #endif dxx-rebirth-0.58.1-d1x/main/textures.h000066400000000000000000000017561217717257200175430ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Array of textures, and other stuff * */ #ifndef _TEXTURES_H #define _TEXTURES_H #include "bm.h" #include "piggy.h" // Texture stuff... in mglobal.c extern int NumTextures; extern bitmap_index Textures[MAX_TEXTURES]; // Array of all texture tmaps. #endif dxx-rebirth-0.58.1-d1x/main/titles.c000066400000000000000000000754161217717257200171630ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to display title screens... * */ #include #include #include #ifdef OGL #include "ogl_init.h" #endif #include "pstypes.h" #include "timer.h" #include "key.h" #include "gr.h" #include "palette.h" #include "iff.h" #include "pcx.h" #include "u_mem.h" #include "joy.h" #include "gamefont.h" #include "dxxerror.h" #include "polyobj.h" #include "textures.h" #include "screens.h" #include "multi.h" #include "player.h" #include "digi.h" #include "text.h" #include "kmatrix.h" #include "piggy.h" #include "songs.h" #include "newmenu.h" #include "menu.h" #include "mouse.h" #include "console.h" #include "args.h" #define MAX_BRIEFING_COLORS 7 #define DEFAULT_BRIEFING_BKG "brief03.pcx" static int Briefing_text_colors[MAX_BRIEFING_COLORS]; static int Current_color = 0; static int Erase_color; // added by Jan Bobrowski for variable-size menu screen static int rescale_x(int x) { return x * GWIDTH / 320; } static int rescale_y(int y) { return y * GHEIGHT / 200; } typedef struct title_screen { grs_bitmap title_bm; fix64 timer; int allow_keys; } title_screen; static int title_handler(window *wind, d_event *event, title_screen *ts) { switch (event->type) { case EVENT_MOUSE_BUTTON_DOWN: if (event_mouse_get_button(event) != 0) return 0; else if (ts->allow_keys) { window_close(wind); return 1; } break; case EVENT_KEY_COMMAND: if (!call_default_handler(event)) if (ts->allow_keys) window_close(wind); return 1; case EVENT_IDLE: timer_delay2(50); if (timer_query() > ts->timer) { window_close(wind); return 1; } break; case EVENT_WINDOW_DRAW: gr_set_current_canvas( NULL ); show_fullscr(&ts->title_bm); break; case EVENT_WINDOW_CLOSE: gr_free_bitmap_data (&ts->title_bm); d_free(ts); break; default: break; } return 0; } static int show_title_screen( char * filename, int allow_keys, int from_hog_only ) { title_screen *ts; window *wind; int pcx_error; char new_filename[PATH_MAX] = ""; MALLOC(ts, title_screen, 1); if (!ts) return 0; ts->allow_keys = allow_keys; #ifdef RELEASE if (from_hog_only) strcpy(new_filename,"\x01"); //only read from hog file #endif strcat(new_filename,filename); filename = new_filename; gr_init_bitmap_data (&ts->title_bm); if ((pcx_error=pcx_read_bitmap( filename, &ts->title_bm, BM_LINEAR, gr_palette ))!=PCX_ERROR_NONE) { Error( "Error loading briefing screen <%s>, PCX load error: %s (%i)\n",filename, pcx_errormsg(pcx_error), pcx_error); } ts->timer = timer_query() + i2f(3); gr_palette_load( gr_palette ); wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))title_handler, ts); if (!wind) { gr_free_bitmap_data (&ts->title_bm); d_free(ts); return 0; } while (window_exists(wind)) event_process(); return 0; } void show_titles(void) { char publisher[PATH_MAX]; songs_play_song( SONG_TITLE, 1 ); if (GameArg.SysNoTitles) return; strcpy(publisher, "macplay.pcx"); // Mac Shareware if (!PHYSFSX_exists(publisher,1)) strcpy(publisher, "mplaycd.pcx"); // Mac Registered if (!PHYSFSX_exists(publisher,1)) strcpy(publisher, "iplogo1.pcx"); // PC. Only down here because it's lowres ;-) show_title_screen( publisher, 1, 1 ); show_title_screen( (((SWIDTH>=640&&SHEIGHT>=480) && PHYSFSX_exists("logoh.pcx",1))?"logoh.pcx":"logo.pcx"), 1, 1 ); show_title_screen( (((SWIDTH>=640&&SHEIGHT>=480) && PHYSFSX_exists("descenth.pcx",1))?"descenth.pcx":"descent.pcx"), 1, 1 ); } void show_order_form() { char exit_screen[PATH_MAX]; if (GameArg.SysNoTitles) return; strcpy(exit_screen, "warning.pcx"); // D1 Registered if (! PHYSFSX_exists(exit_screen,1)) strcpy(exit_screen, "apple.pcx"); // D1 Mac OEM Demo if (! PHYSFSX_exists(exit_screen,1)) strcpy(exit_screen, "order01.pcx"); // D1 Demo show_title_screen(exit_screen, 1, 1); } //----------------------------------------------------------------------------- typedef struct { char bs_name[PATH_MAX]; // filename, eg merc01. Assumes .lbm suffix. sbyte level_num; sbyte message_num; short text_ulx, text_uly; // upper left x,y of text window short text_width, text_height; // width and height of text window } briefing_screen; #define BRIEFING_SECRET_NUM 31 // This must correspond to the first secret level which must come at the end of the list. #define BRIEFING_OFFSET_NUM 4 // This must correspond to the first level screen (ie, past the bald guy briefing screens) #define ENDING_LEVEL_NUM_OEMSHARE 0x7f #define ENDING_LEVEL_NUM_REGISTER 0x7e briefing_screen Briefing_screens_full[] = { { "brief01.pcx", 0, 1, 13, 140, 290, 59 }, { "brief02.pcx", 0, 2, 27, 34, 257, 177 }, { "brief03.pcx", 0, 3, 20, 22, 257, 177 }, { "brief02.pcx", 0, 4, 27, 34, 257, 177 }, { "moon01.pcx", 1, 5, 10, 10, 300, 170 }, // level 1 { "moon01.pcx", 2, 6, 10, 10, 300, 170 }, // level 2 { "moon01.pcx", 3, 7, 10, 10, 300, 170 }, // level 3 { "venus01.pcx", 4, 8, 15, 15, 300, 200 }, // level 4 { "venus01.pcx", 5, 9, 15, 15, 300, 200 }, // level 5 { "brief03.pcx", 6, 10, 20, 22, 257, 177 }, { "merc01.pcx", 6, 11, 10, 15, 300, 200 }, // level 6 { "merc01.pcx", 7, 12, 10, 15, 300, 200 }, // level 7 { "brief03.pcx", 8, 13, 20, 22, 257, 177 }, { "mars01.pcx", 8, 14, 10, 100, 300, 200 }, // level 8 { "mars01.pcx", 9, 15, 10, 100, 300, 200 }, // level 9 { "brief03.pcx", 10, 16, 20, 22, 257, 177 }, { "mars01.pcx", 10, 17, 10, 100, 300, 200 }, // level 10 { "jup01.pcx", 11, 18, 10, 40, 300, 200 }, // level 11 { "jup01.pcx", 12, 19, 10, 40, 300, 200 }, // level 12 { "brief03.pcx", 13, 20, 20, 22, 257, 177 }, { "jup01.pcx", 13, 21, 10, 40, 300, 200 }, // level 13 { "jup01.pcx", 14, 22, 10, 40, 300, 200 }, // level 14 { "saturn01.pcx", 15, 23, 10, 40, 300, 200 }, // level 15 { "brief03.pcx", 16, 24, 20, 22, 257, 177 }, { "saturn01.pcx", 16, 25, 10, 40, 300, 200 }, // level 16 { "brief03.pcx", 17, 26, 20, 22, 257, 177 }, { "saturn01.pcx", 17, 27, 10, 40, 300, 200 }, // level 17 { "uranus01.pcx", 18, 28, 100, 100, 300, 200 }, // level 18 { "uranus01.pcx", 19, 29, 100, 100, 300, 200 }, // level 19 { "uranus01.pcx", 20, 30, 100, 100, 300, 200 }, // level 20 { "uranus01.pcx", 21, 31, 100, 100, 300, 200 }, // level 21 { "neptun01.pcx", 22, 32, 10, 20, 300, 200 }, // level 22 { "neptun01.pcx", 23, 33, 10, 20, 300, 200 }, // level 23 { "neptun01.pcx", 24, 34, 10, 20, 300, 200 }, // level 24 { "pluto01.pcx", 25, 35, 10, 20, 300, 200 }, // level 25 { "pluto01.pcx", 26, 36, 10, 20, 300, 200 }, // level 26 { "pluto01.pcx", 27, 37, 10, 20, 300, 200 }, // level 27 { "aster01.pcx", -1, 38, 10, 90, 300, 200 }, // secret level -1 { "aster01.pcx", -2, 39, 10, 90, 300, 200 }, // secret level -2 { "aster01.pcx", -3, 40, 10, 90, 300, 200 }, // secret level -3 { "end01.pcx", ENDING_LEVEL_NUM_OEMSHARE, 1, 23, 40, 320, 200 }, // OEM and shareware end { "end02.pcx", ENDING_LEVEL_NUM_REGISTER, 1, 5, 5, 300, 200 }, // registered end { "end01.pcx", ENDING_LEVEL_NUM_REGISTER, 2, 23, 40, 320, 200 }, // registered end { "end03.pcx", ENDING_LEVEL_NUM_REGISTER, 3, 5, 5, 300, 200 }, // registered end }; briefing_screen Briefing_screens_share[] = { { "brief01.pcx", 0, 1, 13, 140, 290, 59 }, { "brief02.pcx", 0, 2, 27, 34, 257, 177 }, { "brief03.pcx", 0, 3, 20, 22, 257, 177 }, { "brief02.pcx", 0, 4, 27, 34, 257, 177 }, { "moon01.pcx", 1, 5, 10, 10, 300, 170 }, // level 1 { "moon01.pcx", 2, 6, 10, 10, 300, 170 }, // level 2 { "moon01.pcx", 3, 7, 10, 10, 300, 170 }, // level 3 { "venus01.pcx", 4, 8, 15, 15, 300, 200 }, // level 4 { "venus01.pcx", 5, 9, 15, 15, 300, 200 }, // level 5 { "brief03.pcx", 6, 10, 20, 22, 257, 177 }, { "merc01.pcx", 6, 10, 10, 15, 300, 200 }, // level 6 { "merc01.pcx", 7, 11, 10, 15, 300, 200 }, // level 7 { "end01.pcx", ENDING_LEVEL_NUM_OEMSHARE, 1, 23, 40, 320, 200 }, // shareware end }; #define Briefing_screens ((PHYSFSX_fsize("descent.hog")==D1_SHAREWARE_MISSION_HOGSIZE || PHYSFSX_fsize("descent.hog")==D1_SHAREWARE_10_MISSION_HOGSIZE)?Briefing_screens_share:Briefing_screens_full) #define MAX_BRIEFING_SCREEN ((PHYSFSX_fsize("descent.hog")==D1_SHAREWARE_MISSION_HOGSIZE || PHYSFSX_fsize("descent.hog")==D1_SHAREWARE_10_MISSION_HOGSIZE)?(sizeof(Briefing_screens_share) / sizeof(Briefing_screens_share[0])):(sizeof(Briefing_screens_full) / sizeof(Briefing_screens_full[0]))) typedef struct msgstream { int x; int y; int color; int ch; } __pack__ msgstream; typedef struct briefing { short level_num; short cur_screen; briefing_screen *screen; grs_bitmap background; char background_name[PATH_MAX]; char *text; char *message; int text_x, text_y; msgstream messagestream[2048]; int streamcount; short tab_stop; ubyte flashing_cursor; ubyte new_page; int new_screen; fix64 start_time; fix64 delay_count; int robot_num; grs_canvas *robot_canv; vms_angvec robot_angles; char bitmap_name[32]; grs_bitmap guy_bitmap; sbyte guy_bitmap_show; sbyte door_dir, door_div_count, animating_bitmap_type; sbyte prev_ch; } briefing; static void briefing_init(briefing *br, short level_num) { br->level_num = level_num; if (br->level_num == 1) br->level_num = 0; // for start of game stuff br->cur_screen = 0; br->screen = NULL; gr_init_bitmap_data (&br->background); strncpy(br->background_name, DEFAULT_BRIEFING_BKG, sizeof(br->background_name)); br->robot_num = 0; br->robot_canv = NULL; br->robot_angles.p = br->robot_angles.b = br->robot_angles.h = 0; br->bitmap_name[0] = '\0'; br->door_dir = 1; br->door_div_count = 0; br->animating_bitmap_type = 0; } //----------------------------------------------------------------------------- // Load Descent briefing text. static int load_screen_text(char *filename, char **buf) { PHYSFS_file *tfile; int len, have_binary = 0; char *ext; if ((ext = strrchr(filename, '.')) == NULL) return (0); if (!d_stricmp(ext, ".txb")) have_binary = 1; if ((tfile = PHYSFSX_openReadBuffered(filename)) == NULL) return (0); len = PHYSFS_fileLength(tfile); MALLOC(*buf, char, len+1); PHYSFS_read(tfile, *buf, 1, len); PHYSFS_close(tfile); if (have_binary) decode_text(*buf, len); *(*buf+len)='\0'; return (1); } static int get_message_num(char **message) { int num=0; while (strlen(*message) > 0 && **message == ' ') (*message)++; while (strlen(*message) > 0 && (**message >= '0') && (**message <= '9')) { num = 10*num + **message-'0'; (*message)++; } while (strlen(*message) > 0 && *(*message)++ != 10) // Get and drop eoln ; return num; } static void get_message_name(char **message, char *result) { while (strlen(*message) > 0 && **message == ' ') (*message)++; while (strlen(*message) > 0 && (**message != ' ') && (**message != 10)) { if (**message != '\n') *result++ = **message; (*message)++; } if (**message != 10) while (strlen(*message) > 0 && *(*message)++ != 10) // Get and drop eoln ; *result = 0; } // Return a pointer to the start of text for screen #screen_num. static char * get_briefing_message(briefing *br, int screen_num) { char *tptr = br->text; int cur_screen=0; int ch; Assert(screen_num >= 0); while ( (*tptr != 0 ) && (screen_num != cur_screen)) { ch = *tptr++; if (ch == '$') { ch = *tptr++; if (ch == 'S') cur_screen = get_message_num(&tptr); } } if (screen_num!=cur_screen) return (NULL); return tptr; } static void init_char_pos(briefing *br, int x, int y) { br->text_x = x; br->text_y = y; } // Make sure the text stays on the screen // Return 1 if new page required // 0 otherwise static int check_text_pos(briefing *br) { if (br->text_x > br->screen->text_ulx + br->screen->text_width) { br->text_x = br->screen->text_ulx; br->text_y += br->screen->text_uly; } if (br->text_y > br->screen->text_uly + br->screen->text_height) { br->new_page = 1; return 1; } return 0; } static void put_char_delay(briefing *br, int ch) { char str[2]; int w, h, aw; str[0] = ch; str[1] = '\0'; if (br->delay_count && (timer_query() < br->start_time + br->delay_count)) { br->message--; // Go back to same character return; } br->messagestream[br->streamcount].x = br->text_x; br->messagestream[br->streamcount].y = br->text_y; br->messagestream[br->streamcount].color = Briefing_text_colors[Current_color]; br->messagestream[br->streamcount].ch = ch; br->streamcount++; br->prev_ch = ch; gr_get_string_size(str, &w, &h, &aw ); br->text_x += w; br->start_time = timer_query(); } static void init_spinning_robot(briefing *br); static int load_briefing_screen(briefing *br, char *fname); // Process a character for the briefing, // including special characters preceded by a '$'. // Return 1 when page is finished, 0 otherwise static int briefing_process_char(briefing *br) { int ch; gr_set_curfont( GAME_FONT ); ch = *br->message++; if (ch == '$') { ch = *br->message++; if (ch == 'C') { Current_color = get_message_num(&br->message)-1; if (Current_color < 0) Current_color = 0; else if (Current_color > MAX_BRIEFING_COLORS-1) Current_color = MAX_BRIEFING_COLORS-1; br->prev_ch = 10; } else if (ch == 'F') { // toggle flashing cursor br->flashing_cursor = !br->flashing_cursor; br->prev_ch = 10; while (*br->message++ != 10) ; } else if (ch == 'T') { br->tab_stop = get_message_num(&br->message); br->prev_ch = 10; // read to eoln } else if (ch == 'R') { if (br->robot_canv != NULL) { d_free(br->robot_canv); br->robot_canv=NULL; } init_spinning_robot(br); br->robot_num = get_message_num(&br->message); #if 0 // NOTE: code we wanted to merge from D2. However it breaks the briefing screen of the "Spider" bot: swallows it's name line while (*br->message++ != 10) ; #endif br->prev_ch = 10; // read to eoln } else if (ch == 'N') { if (br->robot_canv != NULL) { d_free(br->robot_canv); br->robot_canv=NULL; } get_message_name(&br->message, br->bitmap_name); strcat(br->bitmap_name, "#0"); br->animating_bitmap_type = 0; br->prev_ch = 10; } else if (ch == 'O') { if (br->robot_canv != NULL) { d_free(br->robot_canv); br->robot_canv=NULL; } get_message_name(&br->message, br->bitmap_name); strcat(br->bitmap_name, "#0"); br->animating_bitmap_type = 1; br->prev_ch = 10; } else if (ch == 'B') { char bitmap_name[32]; ubyte temp_palette[768]; int iff_error; (void)iff_error; if (br->robot_canv != NULL) { d_free(br->robot_canv); br->robot_canv=NULL; } get_message_name(&br->message, bitmap_name); strcat(bitmap_name, ".bbm"); gr_init_bitmap_data (&br->guy_bitmap); iff_error = iff_read_bitmap(bitmap_name, &br->guy_bitmap, BM_LINEAR, temp_palette); Assert(iff_error == IFF_NO_ERROR); br->guy_bitmap_show=1; br->prev_ch = 10; } else if (ch == 'S') { br->new_screen = 1; return 1; } else if (ch == 'P') { // New page. br->new_page = 1; while (*br->message != 10) { br->message++; // drop carriage return after special escape sequence } br->message++; br->prev_ch = 10; return 1; } else if (ch == '$' || ch == ';') // Print a $/; put_char_delay(br, ch); } else if (ch == '\t') { // Tab if (br->text_x - br->screen->text_ulx < FSPACX(br->tab_stop)) br->text_x = br->screen->text_ulx + FSPACX(br->tab_stop); } else if ((ch == ';') && (br->prev_ch == 10)) { while (*br->message++ != 10) ; br->prev_ch = 10; } else if (ch == '\\') { br->prev_ch = ch; } else if (ch == 10) { if (br->prev_ch != '\\') { br->prev_ch = ch; br->text_y += FSPACY(5)+FSPACY(5)*3/5; br->text_x = br->screen->text_ulx; if (br->text_y > br->screen->text_uly + br->screen->text_height) { load_briefing_screen(br, Briefing_screens[br->cur_screen].bs_name); br->text_x = br->screen->text_ulx; br->text_y = br->screen->text_uly; } } else { if (ch == 13) //Can this happen? Above says ch==10 Int3(); br->prev_ch = ch; } } else put_char_delay(br, ch); return 0; } static void set_briefing_fontcolor () { Briefing_text_colors[0] = gr_find_closest_color_current( 0, 40, 0); Briefing_text_colors[1] = gr_find_closest_color_current( 40, 33, 35); Briefing_text_colors[2] = gr_find_closest_color_current( 8, 31, 54); //green Briefing_text_colors[0] = gr_find_closest_color_current( 0, 54, 0); //white Briefing_text_colors[1] = gr_find_closest_color_current( 42, 38, 32); //Begin D1X addition //red Briefing_text_colors[2] = gr_find_closest_color_current( 63, 0, 0); //blue Briefing_text_colors[3] = gr_find_closest_color_current( 0, 0, 54); //gray Briefing_text_colors[4] = gr_find_closest_color_current( 14, 14, 14); //yellow Briefing_text_colors[5] = gr_find_closest_color_current( 54, 54, 0); //purple Briefing_text_colors[6] = gr_find_closest_color_current( 0, 54, 54); //End D1X addition Erase_color = gr_find_closest_color_current(0, 0, 0); } static void redraw_messagestream(msgstream *stream, int count) { char msgbuf[2]; int i; for (i=0; i (F1_0/4)) gr_set_fontcolor(Briefing_text_colors[Current_color], -1); else gr_set_fontcolor(Erase_color, -1); gr_printf(br->text_x, br->text_y, "_" ); } #define EXIT_DOOR_MAX 14 #define OTHER_THING_MAX 10 // Adam: This is the number of frames in your new animating thing. #define DOOR_DIV_INIT 6 //----------------------------------------------------------------------------- static void show_animated_bitmap(briefing *br) { grs_canvas *curcanv_save, *bitmap_canv=0; grs_bitmap *bitmap_ptr; #ifdef OGL float scale = 1.0; if (((float)SWIDTH/320) < ((float)SHEIGHT/200)) scale = ((float)SWIDTH/320); else scale = ((float)SHEIGHT/200); #endif // Only plot every nth frame. if (br->door_div_count) { if (br->bitmap_name[0] != 0) { bitmap_index bi; bi = piggy_find_bitmap(br->bitmap_name); bitmap_ptr = &GameBitmaps[bi.index]; PIGGY_PAGE_IN( bi ); #ifdef OGL ogl_ubitmapm_cs(rescale_x(220), rescale_y(45),bitmap_ptr->bm_w*scale,bitmap_ptr->bm_h*scale,bitmap_ptr,255,F1_0); #else gr_bitmapm(rescale_x(220), rescale_y(45), bitmap_ptr); #endif } br->door_div_count--; return; } br->door_div_count = DOOR_DIV_INIT; if (br->bitmap_name[0] != 0) { char *pound_signp; int num, dig1, dig2; bitmap_index bi; switch (br->animating_bitmap_type) { case 0: bitmap_canv = gr_create_sub_canvas(grd_curcanv, rescale_x(220), rescale_y(45), 64, 64); break; case 1: bitmap_canv = gr_create_sub_canvas(grd_curcanv, rescale_x(220), rescale_y(45), 94, 94); break; // Adam: Change here for your new animating bitmap thing. 94, 94 are bitmap size. default: Int3(); // Impossible, illegal value for br->animating_bitmap_type } curcanv_save = grd_curcanv; grd_curcanv = bitmap_canv; pound_signp = strchr(br->bitmap_name, '#'); Assert(pound_signp != NULL); dig1 = *(pound_signp+1); dig2 = *(pound_signp+2); if (dig2 == 0) num = dig1-'0'; else num = (dig1-'0')*10 + (dig2-'0'); switch (br->animating_bitmap_type) { case 0: num += br->door_dir; if (num > EXIT_DOOR_MAX) { num = EXIT_DOOR_MAX; br->door_dir = -1; } else if (num < 0) { num = 0; br->door_dir = 1; } break; case 1: num++; if (num > OTHER_THING_MAX) num = 0; break; } Assert(num < 100); if (num >= 10) { *(pound_signp+1) = (num / 10) + '0'; *(pound_signp+2) = (num % 10) + '0'; *(pound_signp+3) = 0; } else { *(pound_signp+1) = (num % 10) + '0'; *(pound_signp+2) = 0; } bi = piggy_find_bitmap(br->bitmap_name); bitmap_ptr = &GameBitmaps[bi.index]; PIGGY_PAGE_IN( bi ); #ifdef OGL ogl_ubitmapm_cs(0,0,bitmap_ptr->bm_w*scale,bitmap_ptr->bm_h*scale,bitmap_ptr,255,F1_0); #else gr_bitmapm(0, 0, bitmap_ptr); #endif grd_curcanv = curcanv_save; d_free(bitmap_canv); switch (br->animating_bitmap_type) { case 0: if (num == EXIT_DOOR_MAX) { br->door_dir = -1; br->door_div_count = 64; } else if (num == 0) { br->door_dir = 1; br->door_div_count = 64; } break; case 1: break; } } } //----------------------------------------------------------------------------- static void show_briefing_bitmap(grs_bitmap *bmp) { grs_canvas *curcanv_save, *bitmap_canv; #ifdef OGL float scale = 1.0; #endif bitmap_canv = gr_create_sub_canvas(grd_curcanv, rescale_x(220), rescale_y(55), (bmp->bm_w*(SWIDTH/(HIRESMODE ? 640 : 320))),(bmp->bm_h*(SHEIGHT/(HIRESMODE ? 480 : 200)))); curcanv_save = grd_curcanv; gr_set_current_canvas(bitmap_canv); #ifdef OGL if (((float)SWIDTH/(HIRESMODE ? 640 : 320)) < ((float)SHEIGHT/(HIRESMODE ? 480 : 200))) scale = ((float)SWIDTH/(HIRESMODE ? 640 : 320)); else scale = ((float)SHEIGHT/(HIRESMODE ? 480 : 200)); ogl_ubitmapm_cs(0,0,bmp->bm_w*scale,bmp->bm_h*scale,bmp,255,F1_0); #else gr_bitmapm(0, 0, bmp); #endif gr_set_current_canvas(curcanv_save); d_free(bitmap_canv); } //----------------------------------------------------------------------------- static void init_spinning_robot(briefing *br) //(int x,int y,int w,int h) { int x = rescale_x(138); int y = rescale_y(55); int w = rescale_x(166); int h = rescale_y(138); br->robot_canv = gr_create_sub_canvas(grd_curcanv, x, y, w, h); } static void show_spinning_robot_frame(briefing *br, int robot_num) { grs_canvas *curcanv_save; if (robot_num != -1) { br->robot_angles.p = br->robot_angles.b = 0; br->robot_angles.h += 150; curcanv_save = grd_curcanv; grd_curcanv = br->robot_canv; Assert(Robot_info[robot_num].model_num != -1); draw_model_picture(Robot_info[robot_num].model_num, &br->robot_angles); grd_curcanv = curcanv_save; } } //----------------------------------------------------------------------------- #define KEY_DELAY_DEFAULT ((F1_0*20)/1000) static void init_new_page(briefing *br) { br->new_page = 0; br->robot_num = -1; load_briefing_screen(br, br->background_name); br->text_x = br->screen->text_ulx; br->text_y = br->screen->text_uly; br->streamcount=0; if (br->guy_bitmap_show) { gr_free_bitmap_data (&br->guy_bitmap); br->guy_bitmap_show=0; } br->start_time = 0; br->delay_count = KEY_DELAY_DEFAULT; } // ----------------------------------------------------------------------------- #define NEW_END_GUY1 1 #define NEW_END_GUY2 3 static void free_briefing_screen(briefing *br); extern void swap_0_255(grs_bitmap *bmp); // loads a briefing screen static int load_briefing_screen(briefing *br, char *fname) { int pcx_error; char fname2[PATH_MAX], forigin[PATH_MAX]; free_briefing_screen(br); snprintf(fname2, sizeof(char)*PATH_MAX, "%s", fname); snprintf(forigin, sizeof(char)*PATH_MAX, "%s", PHYSFS_getRealDir(fname)); d_strlwr(forigin); // check if we have a hires version of this image (not included in PC-version by default) // Also if this hires image comes via external AddOn pack, only apply if requested image would be loaded from descent.hog - not a seperate mission which might want to show something else. if (SWIDTH >= 640 && SHEIGHT >= 480 && (strstr(forigin,"descent.hog") != NULL)) { char *ptr; if ((ptr = strrchr(fname2,'.'))) *ptr = '\0'; strncat(fname2, "h.pcx", sizeof(char)*PATH_MAX); if (!PHYSFSX_exists(fname2,1)) snprintf(fname2, sizeof(char)*PATH_MAX, "%s", fname); } gr_init_bitmap_data(&br->background); if (d_stricmp(br->background_name, fname2)) strncpy (br->background_name,fname2, sizeof(br->background_name)); if ((!d_stricmp(fname2, "brief02.pcx") || !d_stricmp(fname2, "brief02h.pcx")) && cheats.baldguy) if ( bald_guy_load("btexture.xxx", &br->background, BM_LINEAR, gr_palette) == 0) { return 0; } if ((pcx_error = pcx_read_bitmap(fname2, &br->background, BM_LINEAR, gr_palette))!=PCX_ERROR_NONE) { Error( "Error loading briefing screen <%s>, PCX load error: %s (%i)\n",fname2, pcx_errormsg(pcx_error), pcx_error); } // Hack: Make sure black parts of robot are shown black if (MacPig && gr_palette[0] == 63 && (!d_stricmp(fname2, "brief03.pcx") || !d_stricmp(fname2, "end01.pcx") || !d_stricmp(fname2, "brief03h.pcx") || !d_stricmp(fname2, "end01h.pcx") )) { swap_0_255(&br->background); gr_palette[0] = gr_palette[1] = gr_palette[2] = 0; gr_palette[765] = gr_palette[766] = gr_palette[767] = 63; } show_fullscr(&br->background); gr_palette_load(gr_palette); set_briefing_fontcolor(); MALLOC(br->screen, briefing_screen, 1); if (!br->screen) return 0; memcpy(br->screen, &Briefing_screens[br->cur_screen], sizeof(briefing_screen)); br->screen->text_ulx = rescale_x(br->screen->text_ulx); br->screen->text_uly = rescale_y(br->screen->text_uly); br->screen->text_width = rescale_x(br->screen->text_width); br->screen->text_height = rescale_y(br->screen->text_height); init_char_pos(br, br->screen->text_ulx, br->screen->text_uly); return 1; } static void free_briefing_screen(briefing *br) { if (br->robot_canv != NULL) d_free(br->robot_canv); if (br->screen != NULL) d_free(br->screen); if (br->background.bm_data != NULL) gr_free_bitmap_data (&br->background); } static int new_briefing_screen(briefing *br, int first) { br->new_screen = 0; if (!first) br->cur_screen++; while ((br->cur_screen < MAX_BRIEFING_SCREEN) && (Briefing_screens[br->cur_screen].level_num != br->level_num)) { br->cur_screen++; if ((br->cur_screen == MAX_BRIEFING_SCREEN) && (br->level_num == 0)) { // Showed the pre-game briefing, now show level 1 briefing br->level_num++; br->cur_screen = 0; } } if (br->cur_screen == MAX_BRIEFING_SCREEN) return 0; // finished if (!load_briefing_screen(br, Briefing_screens[br->cur_screen].bs_name)) return 0; br->message = get_briefing_message(br, Briefing_screens[br->cur_screen].message_num); if (br->message==NULL) return 0; Current_color = 0; br->streamcount = 0; br->tab_stop = 0; br->flashing_cursor = 0; br->new_page = 0; br->start_time = 0; br->delay_count = KEY_DELAY_DEFAULT; br->robot_num = -1; br->bitmap_name[0] = 0; br->guy_bitmap_show = 0; br->prev_ch = -1; return 1; } //----------------------------------------------------------------------------- static int briefing_handler(window *wind, d_event *event, briefing *br) { switch (event->type) { case EVENT_WINDOW_ACTIVATED: case EVENT_WINDOW_DEACTIVATED: key_flush(); break; case EVENT_MOUSE_BUTTON_DOWN: if (event_mouse_get_button(event) == 0) { if (br->new_screen) { if (!new_briefing_screen(br, 0)) { window_close(wind); return 1; } } else if (br->new_page) init_new_page(br); else br->delay_count = 0; return 1; } break; case EVENT_KEY_COMMAND: { int key = event_key_get(event); switch (key) { case KEY_ALTED + KEY_B: // B - ALTED... BALT... BALD... get it? cheats.baldguy = !cheats.baldguy; break; case KEY_ESC: window_close(wind); return 1; case KEY_SPACEBAR: case KEY_ENTER: br->delay_count = 0; // fall through default: if (call_default_handler(event)) return 1; else if (br->new_screen) { if (!new_briefing_screen(br, 0)) { window_close(wind); return 1; } } else if (br->new_page) init_new_page(br); break; } break; } case EVENT_WINDOW_DRAW: gr_set_current_canvas(NULL); timer_delay2(50); if (!(br->new_screen || br->new_page)) while (!briefing_process_char(br) && !br->delay_count) { check_text_pos(br); if (br->new_page) break; } check_text_pos(br); if (br->background.bm_data) show_fullscr(&br->background); if (br->guy_bitmap_show) show_briefing_bitmap(&br->guy_bitmap); if (br->bitmap_name[0] != 0) show_animated_bitmap(br); if (br->robot_num != -1) show_spinning_robot_frame(br, br->robot_num); gr_set_curfont( GAME_FONT ); gr_set_fontcolor(Briefing_text_colors[Current_color], -1); redraw_messagestream(br->messagestream, br->streamcount); if (br->new_page || br->new_screen) flash_cursor(br, br->flashing_cursor); else if (br->flashing_cursor) gr_printf(br->text_x, br->text_y, "_"); break; case EVENT_WINDOW_CLOSE: free_briefing_screen(br); d_free(br->text); d_free(br); break; default: break; } return 0; } void do_briefing_screens(char *filename, int level_num) { briefing *br; window *wind; if (!filename || !*filename) return; MALLOC(br, briefing, 1); if (!br) return; briefing_init(br, level_num); if (!load_screen_text(filename, &br->text)) { d_free(br); return; } wind = window_create(&grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, (int (*)(window *, d_event *, void *))briefing_handler, br); if (!wind) { d_free(br->text); d_free(br); return; } if ((songs_is_playing() != SONG_BRIEFING) && (songs_is_playing() != SONG_ENDGAME)) songs_play_song( SONG_BRIEFING, 1 ); set_screen_mode( SCREEN_MENU ); gr_set_current_canvas(NULL); if (!new_briefing_screen(br, 1)) { window_close(wind); return; } // Stay where we are in the stack frame until briefing done // Too complicated otherwise while (window_exists(wind)) event_process(); } void do_end_briefing_screens(char *filename) { int level_num_screen = Current_level_num, showorder = 0; if (!strlen(filename)) return; // no filename, no ending if (d_stricmp(filename, BIMD1_ENDING_FILE_OEM) == 0) { songs_play_song( SONG_ENDGAME, 1 ); level_num_screen = ENDING_LEVEL_NUM_OEMSHARE; showorder = 1; } else if (d_stricmp(filename, BIMD1_ENDING_FILE_SHARE) == 0) { songs_play_song( SONG_BRIEFING, 1 ); level_num_screen = ENDING_LEVEL_NUM_OEMSHARE; showorder = 1; } else { songs_play_song( SONG_ENDGAME, 1 ); level_num_screen = ENDING_LEVEL_NUM_REGISTER; } do_briefing_screens(filename, level_num_screen); if (showorder) show_order_form(); } dxx-rebirth-0.58.1-d1x/main/titles.h000066400000000000000000000020321217717257200171500ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Header for titles.c * */ #ifndef _TITLES_H #define _TITLES_H extern void show_titles(void); extern void do_briefing_screens(char *filename, int level_num); extern void do_end_briefing_screens(char *filename); extern char * get_briefing_screen( int level_num ); extern void show_order_form(void); #endif dxx-rebirth-0.58.1-d1x/main/vclip.c000066400000000000000000000045571217717257200167720ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for vclips. * */ #include "dxxerror.h" #include "inferno.h" #include "vclip.h" #include "weapon.h" //----------------- Variables for video clips ------------------- int Num_vclips = 0; vclip Vclip[VCLIP_MAXNUM]; // General purpose vclips. //draw an object which renders as a vclip void draw_vclip_object(object *obj,fix timeleft,int lighted, int vclip_num) { int nf,bitmapnum; nf = Vclip[vclip_num].num_frames; bitmapnum = (nf - f2i(fixdiv( (nf-1)*timeleft,Vclip[vclip_num].play_time))) - 1; if (bitmapnum >= Vclip[vclip_num].num_frames) bitmapnum=Vclip[vclip_num].num_frames-1; if (bitmapnum >= 0 ) { if (Vclip[vclip_num].flags & VF_ROD) draw_object_tmap_rod(obj, Vclip[vclip_num].frames[bitmapnum],lighted); else { Assert(lighted==0); //blob cannot now be lighted draw_object_blob(obj, Vclip[vclip_num].frames[bitmapnum] ); } } } void draw_weapon_vclip(object *obj) { int vclip_num; fix modtime; vclip_num = Weapon_info[obj->id].weapon_vclip; modtime = obj->lifeleft; while (modtime > Vclip[vclip_num].play_time) modtime -= Vclip[vclip_num].play_time; draw_vclip_object(obj, modtime, 0, vclip_num); } /* * reads n vclip structs from a PHYSFS_file */ int vclip_read_n(vclip *vc, int n, PHYSFS_file *fp) { int i, j; for (i = 0; i < n; i++) { vc[i].play_time = PHYSFSX_readFix(fp); vc[i].num_frames = PHYSFSX_readInt(fp); vc[i].frame_time = PHYSFSX_readFix(fp); vc[i].flags = PHYSFSX_readInt(fp); vc[i].sound_num = PHYSFSX_readShort(fp); for (j = 0; j < VCLIP_MAX_FRAMES; j++) vc[i].frames[j].index = PHYSFSX_readShort(fp); vc[i].light_value = PHYSFSX_readFix(fp); } return i; } dxx-rebirth-0.58.1-d1x/main/vclip.h000066400000000000000000000036121217717257200167660ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Stuff for video clips. * */ #ifndef _VCLIP_H #define _VCLIP_H #include "gr.h" #include "object.h" #include "piggy.h" #define VCLIP_SMALL_EXPLOSION 2 #define VCLIP_PLAYER_HIT 1 #define VCLIP_MORPHING_ROBOT 10 #define VCLIP_PLAYER_APPEARANCE 61 #define VCLIP_POWERUP_DISAPPEARANCE 62 #define VCLIP_VOLATILE_WALL_HIT 5 #define VCLIP_MAXNUM 70 #define VCLIP_MAX_FRAMES 30 // vclip flags #define VF_ROD 1 // draw as a rod, not a blob typedef struct { fix play_time; // total time (in seconds) of clip int num_frames; fix frame_time; // time (in seconds) of each frame int flags; short sound_num; bitmap_index frames[VCLIP_MAX_FRAMES]; fix light_value; } __pack__ vclip; extern int Num_vclips; extern vclip Vclip[VCLIP_MAXNUM]; // draw an object which renders as a vclip. void draw_vclip_object(object *obj, fix timeleft, int lighted, int vclip_num); extern void draw_weapon_vclip(object *obj); /* * reads n vclip structs from a PHYSFS_file */ extern int vclip_read_n(vclip *vc, int n, PHYSFS_file *fp); #endif /* _VCLIP_H */ dxx-rebirth-0.58.1-d1x/main/vers_id.c000066400000000000000000000003601217717257200172740ustar00rootroot00000000000000#include "vers_id.h" #ifndef DESCENT_VERSION_EXTRA #define DESCENT_VERSION_EXTRA "v" VERSION #endif const char g_descent_version[40] = "D1X-Rebirth " DESCENT_VERSION_EXTRA; const char g_descent_build_datetime[21] = __DATE__ " " __TIME__; dxx-rebirth-0.58.1-d1x/main/vers_id.h000066400000000000000000000011111217717257200172740ustar00rootroot00000000000000/* Version defines */ #ifndef _VERS_ID #define _VERS_ID #define __stringize2(X) #X #define __stringize(X) __stringize2(X) #define DXX_VERSION_MAJOR __stringize(DXX_VERSION_MAJORi) #define DXX_VERSION_MINOR __stringize(DXX_VERSION_MINORi) #define DXX_VERSION_MICRO __stringize(DXX_VERSION_MICROi) #define BASED_VERSION "Registered v1.5 Jan 5, 1996" #define VERSION DXX_VERSION_MAJOR "." DXX_VERSION_MINOR "." DXX_VERSION_MICRO #define DESCENT_VERSION g_descent_version extern const char g_descent_version[40]; extern const char g_descent_build_datetime[21]; #endif /* _VERS_ID */ dxx-rebirth-0.58.1-d1x/main/wall.c000066400000000000000000000762661217717257200166220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Destroyable wall stuff * */ #include #include #include #include #include "gr.h" #include "wall.h" #include "switch.h" #include "inferno.h" #ifdef EDITOR #include "editor/editor.h" #endif #include "segment.h" #include "dxxerror.h" #include "gameseg.h" #include "game.h" #include "bm.h" #include "vclip.h" #include "player.h" #include "gauges.h" #include "text.h" #include "fireball.h" #include "textures.h" #include "sounds.h" #include "newdemo.h" #include "multi.h" #include "gameseq.h" #include "byteswap.h" void kill_stuck_objects(int wallnum); // Special door on boss level which is locked if not in multiplayer...sorry for this awful solution --MK. #define BOSS_LOCKED_DOOR_LEVEL 7 #define BOSS_LOCKED_DOOR_SEG 595 #define BOSS_LOCKED_DOOR_SIDE 5 wall Walls[MAX_WALLS]; // Master walls array int Num_walls=0; // Number of walls wclip WallAnims[MAX_WALL_ANIMS]; // Wall animations int Num_wall_anims; //--unused-- int walls_bm_num[MAX_WALL_ANIMS]; //door Doors[MAX_DOORS]; // Master doors array active_door ActiveDoors[MAX_DOORS]; int Num_open_doors; // Number of open doors //--unused-- grs_bitmap *wall_title_bms[MAX_WALL_ANIMS]; //#define BM_FLAG_TRANSPARENT 1 //#define BM_FLAG_SUPER_TRANSPARENT 2 #ifdef EDITOR char Wall_names[7][10] = { "NORMAL ", "BLASTABLE", "DOOR ", "ILLUSION ", "OPEN ", "CLOSED ", "EXTERNAL " }; #endif // This function determines whether the current segment/side is transparent // 1 = YES // 0 = NO int check_transparency( segment * seg, int side ) { if ( (seg->sides[side].tmap_num2 & 0x3FFF) == 0) { if (GameBitmaps[Textures[seg->sides[side].tmap_num].index].bm_flags & BM_FLAG_TRANSPARENT ) return 1; else return 0; } if (GameBitmaps[Textures[seg->sides[side].tmap_num2 & 0x3FFF ].index].bm_flags & BM_FLAG_SUPER_TRANSPARENT ) return 1; else return 0; } //----------------------------------------------------------------- // This function checks whether we can fly through the given side. // In other words, whether or not we have a 'doorway' // Flags: // WID_FLY_FLAG 1 // WID_RENDER_FLAG 2 // WID_RENDPAST_FLAG 4 // Return values: // WID_WALL 2 // 0/1/0 wall // WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall // WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall // WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall // WID_NO_WALL 5 // 1/0/1 no wall, can fly through int wall_is_doorway ( segment * seg, int side ) { int flags, type; int state; //--Covered by macro // No child. //--Covered by macro if (seg->children[side] == -1) //--Covered by macro return WID_WALL; //--Covered by macro if (seg->children[side] == -2) //--Covered by macro return WID_EXTERNAL_FLAG; //--Covered by macro // No wall present. //--Covered by macro if (seg->sides[side].wall_num == -1) //--Covered by macro return WID_NO_WALL; Assert(seg-Segments>=0 && seg-Segments<=Highest_segment_index); Assert(side>=0 && side<6); type = Walls[seg->sides[side].wall_num].type; flags = Walls[seg->sides[side].wall_num].flags; if (type == WALL_OPEN) return WID_NO_WALL; if (type == WALL_ILLUSION) { if (Walls[seg->sides[side].wall_num].flags & WALL_ILLUSION_OFF) return WID_NO_WALL; else { if (check_transparency( seg, side)) { return WID_TRANSILLUSORY_WALL; }else return WID_ILLUSORY_WALL; } } if (type == WALL_BLASTABLE) { if (flags & WALL_BLASTED) return WID_TRANSILLUSORY_WALL; if (check_transparency( seg, side)) return WID_TRANSPARENT_WALL; else return WID_WALL; } if (flags & WALL_DOOR_OPENED) return WID_TRANSILLUSORY_WALL; state = Walls[seg->sides[side].wall_num].state; if ((type == WALL_DOOR) && (state == WALL_DOOR_OPENING)) return WID_TRANSPARENT_WALL; // If none of the above flags are set, there is no doorway. if (check_transparency( seg, side)) return WID_TRANSPARENT_WALL; else return WID_WALL; // There are children behind the door. } #ifdef EDITOR //----------------------------------------------------------------- // Initializes all the walls (in other words, no special walls) void wall_init() { int i; Num_walls = 0; for (i=0;isides[side].wall_num; if (i==-1) { return; } Walls[i].segnum = seg-Segments; Walls[i].sidenum = side; Walls[i].type = WALL_NORMAL; Walls[i].flags = 0; Walls[i].hps = 0; Walls[i].trigger = -1; Walls[i].clip_num = -1; Walls[i].linked_wall = -1; } #endif //set the tmap_num or tmap_num2 field for a wall/door void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num) { wclip *anim = &WallAnims[anim_num]; int tmap = anim->frames[frame_num]; if ( Newdemo_state==ND_STATE_PLAYBACK ) return; if (anim->flags & WCF_TMAP1) { if (tmap != seg->sides[side].tmap_num || tmap != csegp->sides[cside].tmap_num) { seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = tmap; if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_wall_set_tmap_num1(seg-Segments,side,csegp-Segments,cside,tmap); } } else { Assert(tmap!=0 && seg->sides[side].tmap_num2!=0); if (tmap != seg->sides[side].tmap_num2 || tmap != csegp->sides[cside].tmap_num2) { seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = tmap; if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_wall_set_tmap_num2(seg-Segments,side,csegp-Segments,cside,tmap); } } } // ------------------------------------------------------------------------------- //when the wall has used all its hitpoints, this will destroy it void blast_blastable_wall(segment *seg, int side) { int Connectside; segment *csegp; int a, n, cwall_num; Assert(seg->sides[side].wall_num != -1); Walls[seg->sides[side].wall_num].hps = -1; //say it's blasted csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); cwall_num = csegp->sides[Connectside].wall_num; kill_stuck_objects(seg->sides[side].wall_num); if (cwall_num > -1) kill_stuck_objects(cwall_num); //if this is an exploding wall, explode it if (WallAnims[Walls[seg->sides[side].wall_num].clip_num].flags & WCF_EXPLODES) explode_wall(seg-Segments,side); else { //if not exploding, set final frame, and make door passable a = Walls[seg->sides[side].wall_num].clip_num; n = WallAnims[a].num_frames; wall_set_tmap_num(seg,side,csegp,Connectside,a,n-1); Walls[seg->sides[side].wall_num].flags |= WALL_BLASTED; if (cwall_num > -1) Walls[cwall_num].flags |= WALL_BLASTED; } } //----------------------------------------------------------------- // Destroys a blastable wall. void wall_destroy(segment *seg, int side) { Assert(seg->sides[side].wall_num != -1); Assert(seg-Segments != 0); if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE) blast_blastable_wall( seg, side ); else Error("Hey bub, you are trying to destroy an indestructable wall."); } //----------------------------------------------------------------- // Deteriorate appearance of wall. (Changes bitmap (paste-ons)) void wall_damage(segment *seg, int side, fix damage) { int a, i, n, cwall_num; if (seg->sides[side].wall_num == -1) { return; } if (Walls[seg->sides[side].wall_num].type != WALL_BLASTABLE) return; if (!(Walls[seg->sides[side].wall_num].flags & WALL_BLASTED) && Walls[seg->sides[side].wall_num].hps >= 0) { int Connectside; segment *csegp; csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); cwall_num = csegp->sides[Connectside].wall_num; Walls[seg->sides[side].wall_num].hps -= damage; if (cwall_num > -1) Walls[cwall_num].hps -= damage; a = Walls[seg->sides[side].wall_num].clip_num; n = WallAnims[a].num_frames; if (Walls[seg->sides[side].wall_num].hps < WALL_HPS*1/n) { blast_blastable_wall( seg, side ); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_door_open(seg-Segments, side,Walls[seg->sides[side].wall_num].flags); #endif } else for (i=0;isides[side].wall_num].hps < WALL_HPS*(n-i)/n) { wall_set_tmap_num(seg,side,csegp,Connectside,a,i); } } } //----------------------------------------------------------------- // Opens a door void wall_open_door(segment *seg, int side) { wall *w; active_door *d; int Connectside=0, wall_num=0, cwall_num=0; segment *csegp; Assert(seg->sides[side].wall_num != -1); //Opening door on illegal wall w = &Walls[seg->sides[side].wall_num]; wall_num = w - Walls; //kill_stuck_objects(seg->sides[side].wall_num); if ((w->state == WALL_DOOR_OPENING) || //already opening (w->state == WALL_DOOR_WAITING)) //open, waiting to close return; if (w->state == WALL_DOOR_CLOSING) { //closing, so reuse door int i; d = NULL; for (i=0;ifront_wallnum[0]==w-Walls || d->back_wallnum[0]==wall_num || (d->n_parts==2 && (d->front_wallnum[1]==wall_num || d->back_wallnum[1]==wall_num))) break; } if (i>=Num_open_doors) // likely in demo playback or multiplayer { d = &ActiveDoors[Num_open_doors]; d->time = 0; Num_open_doors++; Assert( Num_open_doors < MAX_DOORS ); } else { Assert( d!=NULL ); // Get John! d->time = WallAnims[w->clip_num].play_time - d->time; if (d->time < 0) d->time = 0; } } else { //create new door Assert(w->state == WALL_DOOR_CLOSED); d = &ActiveDoors[Num_open_doors]; d->time = 0; Num_open_doors++; Assert( Num_open_doors < MAX_DOORS ); } w->state = WALL_DOOR_OPENING; // So that door can't be shot while opening csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); if (Connectside >= 0) { cwall_num = csegp->sides[Connectside].wall_num; if (cwall_num > -1) { Walls[cwall_num].state = WALL_DOOR_OPENING; d->back_wallnum[0] = cwall_num; } d->front_wallnum[0] = seg->sides[side].wall_num; } else con_printf(CON_URGENT, "Illegal Connectside %i in wall_open_door. Trying to hop over. Please check your level!\n", side); Assert( seg-Segments != -1); if (Newdemo_state == ND_STATE_RECORDING) { newdemo_record_door_opening(seg-Segments, side); } if (w->linked_wall != -1) { wall *w2; segment *seg2; w2 = &Walls[w->linked_wall]; seg2 = &Segments[w2->segnum]; Assert(w2->linked_wall == seg->sides[side].wall_num); //Assert(!(w2->flags & WALL_DOOR_OPENING || w2->flags & WALL_DOOR_OPENED)); w2->state = WALL_DOOR_OPENING; csegp = &Segments[seg2->children[w2->sidenum]]; Connectside = find_connect_side(seg2, csegp); Assert(Connectside != -1); if (cwall_num > -1) Walls[cwall_num].state = WALL_DOOR_OPENING; d->n_parts = 2; d->front_wallnum[1] = w->linked_wall; d->back_wallnum[1] = cwall_num; } else d->n_parts = 1; if ( Newdemo_state != ND_STATE_PLAYBACK ) { // NOTE THE LINK TO ABOVE!!!! vms_vector cp; compute_center_point_on_side(&cp, seg, side ); if (WallAnims[w->clip_num].open_sound > -1 ) digi_link_sound_to_pos( WallAnims[w->clip_num].open_sound, seg-Segments, side, &cp, 0, F1_0 ); } } //----------------------------------------------------------------- // This function closes the specified door and restores the closed // door texture. This is called when the animation is done void wall_close_door(int door_num) { int p; active_door *d; int i; d = &ActiveDoors[door_num]; for (p=0;pn_parts;p++) { wall *w; int Connectside, side; segment *csegp, *seg; w = &Walls[d->front_wallnum[p]]; seg = &Segments[w->segnum]; side = w->sidenum; Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED; Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSED; wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0); } for (i=door_num;in_parts;p++) { wall *w; int Connectside, side; segment *csegp, *seg; fix time_elapsed, time_total, one_frame; int i, n; w = &Walls[d->front_wallnum[p]]; kill_stuck_objects(d->front_wallnum[p]); kill_stuck_objects(d->back_wallnum[p]); seg = &Segments[w->segnum]; side = w->sidenum; // Assert(seg->sides[side].wall_num != -1); //Trying to do_door_open on illegal wall if (seg->sides[side].wall_num == -1) { con_printf(CON_URGENT, "Trying to do_door_open on illegal wall %i. Please check your level!\n",side); continue; } csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); d->time += FrameTime; time_elapsed = d->time; n = WallAnims[w->clip_num].num_frames; time_total = WallAnims[w->clip_num].play_time; one_frame = time_total/n; i = time_elapsed/one_frame; if (i < n) wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i); if (i> n/2) { Walls[seg->sides[side].wall_num].flags |= WALL_DOOR_OPENED; Walls[csegp->sides[Connectside].wall_num].flags |= WALL_DOOR_OPENED; } if (i >= n-1) { wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,n-1); // If our door is not automatic just remove it from the list. if (!(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)) { for (i=door_num;isides[side].wall_num].state = WALL_DOOR_WAITING; Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_WAITING; ActiveDoors[Num_open_doors].time = 0; //counts up } } } } //----------------------------------------------------------------- // This function closes the specified door and restores the closed // door texture. This is called when the animation is done void wall_close_door_num(int door_num) { int p; active_door *d; int i, cwall_num; d = &ActiveDoors[door_num]; for (p=0;pn_parts;p++) { wall *w; int Connectside, side; segment *csegp, *seg; w = &Walls[d->front_wallnum[p]]; seg = &Segments[w->segnum]; side = w->sidenum; Assert(seg->sides[side].wall_num != -1); //Closing door on illegal wall csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); cwall_num = csegp->sides[Connectside].wall_num; Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSED; if (cwall_num > -1) Walls[cwall_num].state = WALL_DOOR_CLOSED; wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,0); } for (i=door_num;isize && get_seg_masks(&obj->pos,segnum,obj->size,__FILE__,__LINE__).sidemask & (1<front_wallnum[0]]; //check for objects in doorway before closing if (w->flags & WALL_DOOR_AUTO) for (p=0;pn_parts;p++) { int Connectside, side; segment *csegp, *seg; int objnum; seg = &Segments[w->segnum]; side = w->sidenum; csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); //go through each object in each of two segments, and see if //it pokes into the connecting seg for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next) if (check_poke(objnum,seg-Segments,side)) return; //abort! for (objnum=csegp->objects;objnum!=-1;objnum=Objects[objnum].next) if (check_poke(objnum,csegp-Segments,Connectside)) return; //abort! } for (p=0;pn_parts;p++) { wall *w; int Connectside, side; segment *csegp, *seg; fix time_elapsed, time_total, one_frame; int i, n; w = &Walls[d->front_wallnum[p]]; seg = &Segments[w->segnum]; side = w->sidenum; if (seg->sides[side].wall_num == -1) { return; } //if here, must be auto door Assert(Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO); // Otherwise, close it. csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); Assert(Connectside != -1); if ( Newdemo_state != ND_STATE_PLAYBACK ) // NOTE THE LINK TO ABOVE!! if (p==0) //only play one sound for linked doors if ( d->time==0 ) { //first time vms_vector cp; compute_center_point_on_side(&cp, seg, side ); if (WallAnims[w->clip_num].close_sound > -1 ) digi_link_sound_to_pos( WallAnims[Walls[seg->sides[side].wall_num].clip_num].close_sound, seg-Segments, side, &cp, 0, F1_0 ); } d->time += FrameTime; time_elapsed = d->time; n = WallAnims[w->clip_num].num_frames; time_total = WallAnims[w->clip_num].play_time; one_frame = time_total/n; i = n-time_elapsed/one_frame-1; if (i < n/2) { Walls[seg->sides[side].wall_num].flags &= ~WALL_DOOR_OPENED; Walls[csegp->sides[Connectside].wall_num].flags &= ~WALL_DOOR_OPENED; } // Animate door. if (i > 0) { wall_set_tmap_num(seg,side,csegp,Connectside,w->clip_num,i); Walls[seg->sides[side].wall_num].state = WALL_DOOR_CLOSING; Walls[csegp->sides[Connectside].wall_num].state = WALL_DOOR_CLOSING; ActiveDoors[Num_open_doors].time = 0; //counts up } else wall_close_door(door_num); } } //----------------------------------------------------------------- // Turns off an illusionary wall (This will be used primarily for // wall switches or triggers that can turn on/off illusionary walls.) void wall_illusion_off(segment *seg, int side) { segment *csegp; int cside; csegp = &Segments[seg->children[side]]; cside = find_connect_side(seg, csegp); Assert(cside != -1); if (seg->sides[side].wall_num == -1) { return; } Walls[seg->sides[side].wall_num].flags |= WALL_ILLUSION_OFF; Walls[csegp->sides[cside].wall_num].flags |= WALL_ILLUSION_OFF; } //----------------------------------------------------------------- // Turns on an illusionary wall (This will be used primarily for // wall switches or triggers that can turn on/off illusionary walls.) void wall_illusion_on(segment *seg, int side) { segment *csegp; int cside; csegp = &Segments[seg->children[side]]; cside = find_connect_side(seg, csegp); Assert(cside != -1); if (seg->sides[side].wall_num == -1) { return; } Walls[seg->sides[side].wall_num].flags &= ~WALL_ILLUSION_OFF; Walls[csegp->sides[cside].wall_num].flags &= ~WALL_ILLUSION_OFF; } // ----------------------------------------------------------------------------- // Allowed to open the normally locked special boss door if in multiplayer mode. int special_boss_opening_allowed(int segnum, int sidenum) { if (Game_mode & GM_MULTI) return (Current_level_num == BOSS_LOCKED_DOOR_LEVEL) && (segnum == BOSS_LOCKED_DOOR_SEG) && (sidenum == BOSS_LOCKED_DOOR_SIDE); else return 0; } //----------------------------------------------------------------- // Determines what happens when a wall is shot //returns info about wall. see wall.h for codes //obj is the object that hit...either a weapon or the player himself //playernum is the number the player who hit the wall or fired the weapon, //or -1 if a robot fired the weapon int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj ) { wall *w; fix show_message; Assert (seg-Segments != -1); // If it is not a "wall" then just return. if ( seg->sides[side].wall_num < 0 ) return WHP_NOT_SPECIAL; w = &Walls[seg->sides[side].wall_num]; if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_wall_hit_process( seg-Segments, side, damage, playernum ); if (w->type == WALL_BLASTABLE) { wall_damage(seg, side, damage); return WHP_BLASTABLE; } if (playernum != Player_num) //return if was robot fire return WHP_NOT_SPECIAL; Assert( playernum > -1 ); // Determine whether player is facing door he hit. If not, don't say negative // messages because he probably didn't intentionally hit the door. if (obj->type == OBJ_PLAYER) show_message = (vm_vec_dot(&obj->orient.fvec, &obj->mtype.phys_info.velocity) > 0); else show_message = 1; if (w->keys == KEY_BLUE) if (!(Players[playernum].flags & PLAYER_FLAGS_BLUE_KEY)) { if ( playernum==Player_num ) if (show_message) HUD_init_message(HM_DEFAULT, "%s %s",TXT_BLUE,TXT_ACCESS_DENIED); return WHP_NO_KEY; } if (w->keys == KEY_RED) if (!(Players[playernum].flags & PLAYER_FLAGS_RED_KEY)) { if ( playernum==Player_num ) if (show_message) HUD_init_message(HM_DEFAULT, "%s %s",TXT_RED,TXT_ACCESS_DENIED); return WHP_NO_KEY; } if (w->keys == KEY_GOLD) if (!(Players[playernum].flags & PLAYER_FLAGS_GOLD_KEY)) { if ( playernum==Player_num ) if (show_message) HUD_init_message(HM_DEFAULT, "%s %s",TXT_YELLOW,TXT_ACCESS_DENIED); return WHP_NO_KEY; } if (w->type == WALL_DOOR) { if ((w->flags & WALL_DOOR_LOCKED ) && !(special_boss_opening_allowed(seg-Segments, side)) ) { if ( playernum==Player_num ) if (show_message) HUD_init_message_literal(HM_DEFAULT, TXT_CANT_OPEN_DOOR); return WHP_NO_KEY; } else { if (w->state != WALL_DOOR_OPENING) { wall_open_door(seg, side); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_door_open(seg-Segments, side, 0); #endif } return WHP_DOOR; } } return WHP_NOT_SPECIAL; //default is treat like normal wall } //----------------------------------------------------------------- // Opens doors/destroys wall/shuts off triggers. void wall_toggle(int segnum, int side) { int wall_num; if (segnum < 0 || segnum > Highest_segment_index || side < 0 || side >= MAX_SIDES_PER_SEGMENT) { #ifndef NDEBUG Warning("Can't toggle side %d (%i) of\nsegment %d (%i)!\n", side, MAX_SIDES_PER_SEGMENT, segnum, Highest_segment_index); #endif return; } wall_num = Segments[segnum].sides[side].wall_num; if (wall_num == -1) { return; } if ( Newdemo_state == ND_STATE_RECORDING ) newdemo_record_wall_toggle(segnum, side ); if (Walls[wall_num].type == WALL_BLASTABLE) wall_destroy(&Segments[segnum], side); if ((Walls[wall_num].type == WALL_DOOR) && (Walls[wall_num].state == WALL_DOOR_CLOSED)) wall_open_door(&Segments[segnum], side); } //----------------------------------------------------------------- // Tidy up Walls array for load/save purposes. void reset_walls() { int i; if (Num_walls < 0) { return; } for (i=Num_walls;ifront_wallnum[0]]; if (w->state == WALL_DOOR_OPENING) do_door_open(i); else if (w->state == WALL_DOOR_CLOSING) do_door_close(i); else if (w->state == WALL_DOOR_WAITING) { d->time += FrameTime; // set flags to fix occasional netgame problem where door is waiting to close but open flag isn't set // NOTE: Taken from D2 source. Should not be necessary as multi_do_door_open() is more simple than in D2 but add anyways as it's a *good* fallback... w->flags |= WALL_DOOR_OPENED; if (d->back_wallnum[0] > -1) Walls[d->back_wallnum[0]].flags |= WALL_DOOR_OPENED; if (d->time > DOOR_WAIT_TIME) { w->state = WALL_DOOR_CLOSING; d->time = 0; } } } } int Num_stuck_objects=0; stuckobj Stuck_objects[MAX_STUCK_OBJECTS]; // An object got stuck in a door (like a flare). // Add global entry. void add_stuck_object(object *objp, int segnum, int sidenum) { int i; int wallnum; wallnum = Segments[segnum].sides[sidenum].wall_num; if (wallnum != -1) { if (Walls[wallnum].flags & WALL_BLASTED) objp->flags |= OF_SHOULD_BE_DEAD; for (i=0; isignature; Num_stuck_objects++; break; } } } } // -------------------------------------------------------------------------------------------------- // Look at the list of stuck objects, clean up in case an object has gone away, but not been removed here. // Removes up to one/frame. void remove_obsolete_stuck_objects(void) { int objnum; objnum = d_tick_count % MAX_STUCK_OBJECTS; if (Stuck_objects[objnum].wallnum != -1) if ((Stuck_objects[objnum].wallnum == 0) || (Objects[Stuck_objects[objnum].objnum].signature != Stuck_objects[objnum].signature)) { Num_stuck_objects--; Stuck_objects[objnum].wallnum = -1; } } // ---------------------------------------------------------------------------------------------------- // Door with wall index wallnum is opening, kill all objects stuck in it. void kill_stuck_objects(int wallnum) { int i; if (Num_stuck_objects == 0) return; Num_stuck_objects=0; for (i=0; itype = PHYSFSX_readByte(fp); w->flags = PHYSFSX_readByte(fp); w->hps = PHYSFSX_readFix(fp); w->trigger = PHYSFSX_readByte(fp); w->clip_num = PHYSFSX_readByte(fp); w->keys = PHYSFSX_readByte(fp); } /* * reads a v19_wall structure from a PHYSFS_file */ extern void v19_wall_read(v19_wall *w, PHYSFS_file *fp) { w->segnum = PHYSFSX_readInt(fp); w->sidenum = PHYSFSX_readInt(fp); w->type = PHYSFSX_readByte(fp); w->flags = PHYSFSX_readByte(fp); w->hps = PHYSFSX_readFix(fp); w->trigger = PHYSFSX_readByte(fp); w->clip_num = PHYSFSX_readByte(fp); w->keys = PHYSFSX_readByte(fp); w->linked_wall = PHYSFSX_readInt(fp); } /* * reads a wall structure from a PHYSFS_file */ extern void wall_read(wall *w, PHYSFS_file *fp) { w->segnum = PHYSFSX_readInt(fp); w->sidenum = PHYSFSX_readInt(fp); w->hps = PHYSFSX_readFix(fp); w->linked_wall = PHYSFSX_readInt(fp); w->type = PHYSFSX_readByte(fp); w->flags = PHYSFSX_readByte(fp); w->state = PHYSFSX_readByte(fp); w->trigger = PHYSFSX_readByte(fp); w->clip_num = PHYSFSX_readByte(fp); w->keys = PHYSFSX_readByte(fp); /*w->controlling_trigger =*/ PHYSFSX_readByte(fp); /*w->cloak_value =*/ PHYSFSX_readByte(fp); } void wall_swap(wall *w, int swap) { if (!swap) return; w->segnum = SWAPINT(w->segnum); w->sidenum = SWAPINT(w->sidenum); w->hps = SWAPINT(w->hps); w->linked_wall = SWAPINT(w->linked_wall); } /* * reads n wall structs from a PHYSFS_file and swaps if specified */ void wall_read_n_swap(wall *w, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, w, sizeof(wall), n); if (swap) for (i = 0; i < n; i++) wall_swap(&w[i], swap); } /* * reads a v19_door structure from a PHYSFS_file */ extern void v19_door_read(v19_door *d, PHYSFS_file *fp) { d->n_parts = PHYSFSX_readInt(fp); d->seg[0] = PHYSFSX_readShort(fp); d->seg[1] = PHYSFSX_readShort(fp); d->side[0] = PHYSFSX_readShort(fp); d->side[1] = PHYSFSX_readShort(fp); d->type[0] = PHYSFSX_readShort(fp); d->type[1] = PHYSFSX_readShort(fp); d->open = PHYSFSX_readFix(fp); } /* * reads an active_door structure from a PHYSFS_file */ extern void active_door_read(active_door *ad, PHYSFS_file *fp) { ad->n_parts = PHYSFSX_readInt(fp); ad->front_wallnum[0] = PHYSFSX_readShort(fp); ad->front_wallnum[1] = PHYSFSX_readShort(fp); ad->back_wallnum[0] = PHYSFSX_readShort(fp); ad->back_wallnum[1] = PHYSFSX_readShort(fp); ad->time = PHYSFSX_readFix(fp); } void active_door_swap(active_door *ad, int swap) { if (!swap) return; ad->n_parts = SWAPINT(ad->n_parts); ad->front_wallnum[0] = SWAPSHORT(ad->front_wallnum[0]); ad->front_wallnum[1] = SWAPSHORT(ad->front_wallnum[1]); ad->back_wallnum[0] = SWAPSHORT(ad->back_wallnum[0]); ad->back_wallnum[1] = SWAPSHORT(ad->back_wallnum[1]); ad->time = SWAPINT(ad->time); } /* * reads n active_door structs from a PHYSFS_file and swaps if specified */ void active_door_read_n_swap(active_door *ad, int n, int swap, PHYSFS_file *fp) { int i; PHYSFS_read(fp, ad, sizeof(active_door), n); if (swap) for (i = 0; i < n; i++) active_door_swap(&ad[i], swap); } void wall_write(wall *w, short version, PHYSFS_file *fp) { if (version >= 17) { PHYSFS_writeSLE32(fp, w->segnum); PHYSFS_writeSLE32(fp, w->sidenum); } if (version >= 20) { PHYSFSX_writeFix(fp, w->hps); PHYSFS_writeSLE32(fp, w->linked_wall); } PHYSFSX_writeU8(fp, w->type); PHYSFSX_writeU8(fp, w->flags); if (version < 20) PHYSFSX_writeFix(fp, w->hps); else PHYSFSX_writeU8(fp, w->state); PHYSFSX_writeU8(fp, w->trigger); PHYSFSX_writeU8(fp, w->clip_num); PHYSFSX_writeU8(fp, w->keys); if (version >= 20) { PHYSFSX_writeU8(fp, 0); // w->controlling_trigger PHYSFSX_writeU8(fp, 0); // w->cloak_value } else if (version >= 17) PHYSFS_writeSLE32(fp, w->linked_wall); } dxx-rebirth-0.58.1-d1x/main/wall.h000066400000000000000000000234611217717257200166140ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * * */ #ifndef _WALL_H #define _WALL_H #include "inferno.h" #include "segment.h" #include "object.h" //#include "vclip.h" #define MAX_WALLS 175 // Maximum number of walls #define MAX_WALL_ANIMS 30 // Maximum different types of doors #define MAX_DOORS 50 // Maximum number of open doors // not used -> #define MAX_DOOR_ANIMS 20 // Maximum different types of doors // Various wall types. #define WALL_NORMAL 0 // Normal wall #define WALL_BLASTABLE 1 // Removable (by shooting) wall #define WALL_DOOR 2 // Door #define WALL_ILLUSION 3 // Wall that appears to be there, but you can fly thru #define WALL_OPEN 4 // Just an open side. (Trigger) #define WALL_CLOSED 5 // Wall. Used for transparent walls. // Various wall flags. #define WALL_BLASTED 1 // Blasted out wall. #define WALL_DOOR_OPENED 2 // Open door. #define WALL_DOOR_LOCKED 8 // Door is locked. #define WALL_DOOR_AUTO 16 // Door automatically closes after time. #define WALL_ILLUSION_OFF 32 // Illusionary wall is shut off. // Wall states #define WALL_DOOR_CLOSED 0 // Door is closed #define WALL_DOOR_OPENING 1 // Door is opening. #define WALL_DOOR_WAITING 2 // Waiting to close #define WALL_DOOR_CLOSING 3 // Door is closing //note: a door is considered opened (i.e., it has WALL_OPENED set) when it //is more than half way open. Thus, it can have any of OPENING, CLOSING, //or WAITING bits set when OPENED is set. #define KEY_NONE 1 #define KEY_BLUE 2 #define KEY_RED 4 #define KEY_GOLD 8 #define WALL_HPS 100*F1_0 // Normal wall's hp #define WALL_DOOR_INTERVAL 5*F1_0 // How many seconds a door is open #define DOOR_OPEN_TIME i2f(2) // How long takes to open #define DOOR_WAIT_TIME i2f(5) // How long before auto door closes #define MAX_CLIP_FRAMES 20 // WALL_IS_DOORWAY flags. #define WID_FLY_FLAG 1 #define WID_RENDER_FLAG 2 #define WID_RENDPAST_FLAG 4 #define WID_EXTERNAL_FLAG 8 // WALL_IS_DOORWAY return values F/R/RP #define WID_WALL 2 // 0/1/0 wall #define WID_TRANSPARENT_WALL 6 // 0/1/1 transparent wall #define WID_ILLUSORY_WALL 3 // 1/1/0 illusory wall #define WID_TRANSILLUSORY_WALL 7 // 1/1/1 transparent illusory wall #define WID_NO_WALL 5 // 1/0/1 no wall, can fly through #define WID_EXTERNAL 8 // 0/0/0/1 don't see it, dont fly through it #define MAX_STUCK_OBJECTS 32 typedef struct stuckobj { short objnum, wallnum; int signature; } stuckobj; //Start old wall structures typedef struct v16_wall { sbyte type; // What kind of special wall. sbyte flags; // Flags for the wall. fix hps; // "Hit points" of the wall. sbyte trigger; // Which trigger is associated with the wall. sbyte clip_num; // Which animation associated with the wall. sbyte keys; } __pack__ v16_wall; typedef struct v19_wall { int segnum,sidenum; // Seg & side for this wall sbyte type; // What kind of special wall. sbyte flags; // Flags for the wall. fix hps; // "Hit points" of the wall. sbyte trigger; // Which trigger is associated with the wall. sbyte clip_num; // Which animation associated with the wall. sbyte keys; int linked_wall; // number of linked wall } __pack__ v19_wall; typedef struct v19_door { int n_parts; // for linked walls short seg[2]; // Segment pointer of door. short side[2]; // Side number of door. short type[2]; // What kind of door animation. fix open; // How long it has been open. } __pack__ v19_door; //End old wall structures typedef struct wall { int segnum,sidenum; // Seg & side for this wall fix hps; // "Hit points" of the wall. int linked_wall; // number of linked wall ubyte type; // What kind of special wall. ubyte flags; // Flags for the wall. ubyte state; // Opening, closing, etc. sbyte trigger; // Which trigger is associated with the wall. sbyte clip_num; // Which animation associated with the wall. ubyte keys; // which keys are required short pad; // keep longword aligned } __pack__ wall; typedef struct active_door { int n_parts; // for linked walls short front_wallnum[2]; // front wall numbers for this door short back_wallnum[2]; // back wall numbers for this door fix time; // how long been opening, closing, waiting } __pack__ active_door; //wall clip flags #define WCF_EXPLODES 1 //door explodes when opening #define WCF_BLASTABLE 2 //this is a blastable wall #define WCF_TMAP1 4 //this uses primary tmap, not tmap2 #define WCF_HIDDEN 8 //this uses primary tmap, not tmap2 typedef struct { fix play_time; short num_frames; short frames[MAX_CLIP_FRAMES]; short open_sound; short close_sound; short flags; char filename[13]; char pad; } __pack__ wclip; extern char Wall_names[7][10]; //#define WALL_IS_DOORWAY(seg,side) wall_is_doorway(seg, side) #define WALL_IS_DOORWAY(seg,side) (((seg)->children[(side)] == -1) ? WID_WALL : ((seg)->children[(side)] == -2) ? WID_EXTERNAL_FLAG : ((seg)->sides[(side)].wall_num == -1) ? WID_NO_WALL : wall_is_doorway((seg), (side))) extern wall Walls[MAX_WALLS]; // Master walls array extern int Num_walls; // Number of walls extern active_door ActiveDoors[MAX_DOORS]; // Master doors array extern int Num_open_doors; // Number of open doors extern wclip WallAnims[MAX_WALL_ANIMS]; extern int Num_wall_anims; extern int walls_bm_num[MAX_WALL_ANIMS]; // Initializes all walls (i.e. no special walls.) extern void wall_init(); // Automatically checks if a there is a doorway (i.e. can fly through) extern int wall_is_doorway ( segment *seg, int side ); // Deteriorate appearance of wall. (Changes bitmap (paste-ons)) extern void wall_damage(segment *seg, int side, fix damage); // Destroys a blastable wall. (So it is an opening afterwards) extern void wall_destroy(segment *seg, int side); void wall_illusion_on(segment *seg, int side); void wall_illusion_off(segment *seg, int side); // Opens a door, including animation and other processing. void do_door_open(int door_num); // Closes a door, including animation and other processing. void do_door_close(int door_num); // Opens a door extern void wall_open_door(segment *seg, int side); // Closes a door (called after given interval) extern void wall_close_door(int wall_num); //return codes for wall_hit_process() #define WHP_NOT_SPECIAL 0 //wasn't a quote-wall-unquote #define WHP_NO_KEY 1 //hit door, but didn't have key #define WHP_BLASTABLE 2 //hit blastable wall #define WHP_DOOR 3 //a door (which will now be opening) // Determines what happens when a wall is shot //obj is the object that hit...either a weapon or the player himself extern int wall_hit_process(segment *seg, int side, fix damage, int playernum, object *obj ); // Opens/destroys specified door. extern void wall_toggle(int segnum, int side); // Tidy up Walls array for load/save purposes. extern void reset_walls(); // Called once per frame.. void wall_frame_process(); extern stuckobj Stuck_objects[MAX_STUCK_OBJECTS]; // An object got stuck in a door (like a flare). // Add global entry. extern void add_stuck_object(object *objp, int segnum, int sidenum); extern void remove_obsolete_stuck_objects(void); //set the tmap_num or tmap_num2 field for a wall/door extern void wall_set_tmap_num(segment *seg,int side,segment *csegp,int cside,int anim_num,int frame_num); /* * reads n wclip structs from a PHYSFS_file */ extern int wclip_read_n(wclip *wc, int n, PHYSFS_file *fp); /* * reads a v16_wall structure from a PHYSFS_file */ extern void v16_wall_read(v16_wall *w, PHYSFS_file *fp); /* * reads a v19_wall structure from a PHYSFS_file */ extern void v19_wall_read(v19_wall *w, PHYSFS_file *fp); /* * reads a wall structure from a PHYSFS_file */ extern void wall_read(wall *w, PHYSFS_file *fp); /* * reads a v19_door structure from a PHYSFS_file */ extern void v19_door_read(v19_door *d, PHYSFS_file *fp); /* * reads an active_door structure from a PHYSFS_file */ extern void active_door_read(active_door *ad, PHYSFS_file *fp); /* * reads n active_door structs from a PHYSFS_file and swaps if specified */ extern void active_door_read_n_swap(active_door *ad, int n, int swap, PHYSFS_file *fp); /* * reads n wall structs from a PHYSFS_file and swaps if specified */ void wall_read_n_swap(wall *w, int n, int swap, PHYSFS_file *fp); extern void wall_write(wall *w, short version, PHYSFS_file *fp); void wall_close_door_num(int door_num); #endif dxx-rebirth-0.58.1-d1x/main/weapon.c000066400000000000000000000476601217717257200171500ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for weapons... * */ #include "game.h" #include "laser.h" #include "weapon.h" #include "player.h" #include "gauges.h" #include "dxxerror.h" #include "sounds.h" #include "text.h" #include "powerup.h" #include "newdemo.h" #include "multi.h" #include "newmenu.h" #include "playsave.h" // Convert primary weapons to indices in Weapon_info array. const ubyte Primary_weapon_to_weapon_info[MAX_PRIMARY_WEAPONS] = {0, VULCAN_ID, 12, PLASMA_ID, FUSION_ID}; const ubyte Secondary_weapon_to_weapon_info[MAX_SECONDARY_WEAPONS] = {CONCUSSION_ID, HOMING_ID, PROXIMITY_ID, SMART_ID, MEGA_ID}; //for each primary weapon, what kind of powerup gives weapon const ubyte Primary_weapon_to_powerup[MAX_PRIMARY_WEAPONS] = {POW_LASER,POW_VULCAN_WEAPON,POW_SPREADFIRE_WEAPON,POW_PLASMA_WEAPON,POW_FUSION_WEAPON}; //for each Secondary weapon, what kind of powerup gives weapon const ubyte Secondary_weapon_to_powerup[MAX_SECONDARY_WEAPONS] = {POW_MISSILE_1,POW_HOMING_AMMO_1,POW_PROXIMITY_WEAPON,POW_SMARTBOMB_WEAPON,POW_MEGA_WEAPON}; const int Primary_ammo_max[MAX_PRIMARY_WEAPONS] = {0, VULCAN_AMMO_MAX, 0, 0, 0}; const ubyte Secondary_ammo_max[MAX_SECONDARY_WEAPONS] = {20, 10, 10, 5, 5}; weapon_info Weapon_info[MAX_WEAPON_TYPES]; int N_weapon_types=0; sbyte Primary_weapon, Secondary_weapon; int POrderList (int num); int SOrderList (int num); static const ubyte DefaultPrimaryOrder[] = { 4, 3, 2, 1, 0, 255 }; static const ubyte DefaultSecondaryOrder[] = { 4, 3, 1, 0, 255, 2 }; extern ubyte MenuReordering; // ------------------------------------------------------------------------------------ // Return: // Bits set: // HAS_WEAPON_FLAG // HAS_ENERGY_FLAG // HAS_AMMO_FLAG // See weapon.h for bit values int player_has_weapon(int weapon_num, int secondary_flag) { int return_value = 0; int weapon_index; // Hack! If energy goes negative, you can't fire a weapon that doesn't require energy. // But energy should not go negative (but it does), so find out why it does! if (Players[Player_num].energy < 0) Players[Player_num].energy = 0; if (!secondary_flag) { if(weapon_num >= MAX_PRIMARY_WEAPONS) { switch(weapon_num-MAX_PRIMARY_WEAPONS) { case 0 : if((Players[Player_num].laser_level != 0)||(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 1 : if((Players[Player_num].laser_level != 1)||(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 2 : if((Players[Player_num].laser_level != 2)||(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 3 : if((Players[Player_num].laser_level != 3)||(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 4 : if((Players[Player_num].laser_level != 0)||!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 5 : if((Players[Player_num].laser_level != 1)||!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 6 : if((Players[Player_num].laser_level != 2)||!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; case 7 : if((Players[Player_num].laser_level != 3)||!(Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)) return 0; break; } weapon_num = 0; } weapon_index = Primary_weapon_to_weapon_info[weapon_num]; if (Players[Player_num].primary_weapon_flags & (1 << weapon_num)) return_value |= HAS_WEAPON_FLAG; if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].primary_ammo[weapon_num]) return_value |= HAS_AMMO_FLAG; //added on 1/21/99 by Victor Rachels... yet another hack //fusion has 0 energy usage, HAS_ENERGY_FLAG was always true if(weapon_num==FUSION_INDEX) { if(Players[Player_num].energy >= F1_0*2) return_value |= HAS_ENERGY_FLAG; } else //end this section addition - VR if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy) return_value |= HAS_ENERGY_FLAG; } else { weapon_index = Secondary_weapon_to_weapon_info[weapon_num]; if (Players[Player_num].secondary_weapon_flags & (1 << weapon_num)) return_value |= HAS_WEAPON_FLAG; if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].secondary_ammo[weapon_num]) return_value |= HAS_AMMO_FLAG; if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy) return_value |= HAS_ENERGY_FLAG; } return return_value; } void InitWeaponOrdering () { // short routine to setup default weapon priorities for new pilots int i; for (i=0;i= MAX_PRIMARY_WEAPONS+1) // loop if necessary cur_order_slot = 0; if (cur_order_slot == autoselect_order_slot) // what to to with non-autoselect weapons? { if (use_restricted_autoselect) { cur_order_slot = 0; // loop over or ... } else { continue; // continue? } } desired_weapon = PlayerCfg.PrimaryOrder[cur_order_slot]; // now that is the weapon next to our current one // select the weapon if we have it if (player_has_weapon(desired_weapon, 0) == HAS_ALL) { select_weapon(desired_weapon, 0, 1, 1); return; } } } void CycleSecondary () { int cur_order_slot = SOrderList(Secondary_weapon), desired_weapon = Secondary_weapon, loop=0; const int autoselect_order_slot = SOrderList(255); const int use_restricted_autoselect = (cur_order_slot < autoselect_order_slot) && (1 < autoselect_order_slot) && (PlayerCfg.CycleAutoselectOnly); while (loop<(MAX_SECONDARY_WEAPONS+1)) { loop++; cur_order_slot++; // next slot if (cur_order_slot >= MAX_SECONDARY_WEAPONS+1) // loop if necessary cur_order_slot = 0; if (cur_order_slot == autoselect_order_slot) // what to to with non-autoselect weapons? { if (use_restricted_autoselect) { cur_order_slot = 0; // loop over or ... } else { continue; // continue? } } desired_weapon = PlayerCfg.SecondaryOrder[cur_order_slot]; // now that is the weapon next to our current one // select the weapon if we have it if (player_has_weapon(desired_weapon, 1) == HAS_ALL) { select_weapon(desired_weapon, 1, 1, 1); return; } } } // ------------------------------------------------------------------------------------ //if message flag set, print message saying selected void select_weapon(int weapon_num, int secondary_flag, int print_message, int wait_for_rearm) { char *weapon_name; #ifndef SHAREWARE if (Newdemo_state==ND_STATE_RECORDING ) newdemo_record_player_weapon(secondary_flag, weapon_num); #endif if (!secondary_flag) { if (Primary_weapon != weapon_num) { #ifndef FUSION_KEEPS_CHARGE //added 8/6/98 by Victor Rachels to fix fusion charge bug Fusion_charge=0; //end edit - Victor Rachels #endif if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_PRIMARY, F1_0 ); #ifdef NETWORK if (Game_mode & GM_MULTI) { if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0); } #endif if (wait_for_rearm) Next_laser_fire_time = GameTime64 + REARM_TIME; else Next_laser_fire_time = 0; Global_laser_firing_count = 0; } else { if (wait_for_rearm) digi_play_sample( SOUND_ALREADY_SELECTED, F1_0 ); } Primary_weapon = weapon_num; weapon_name = PRIMARY_WEAPON_NAMES(weapon_num); } else { if (Secondary_weapon != weapon_num) { if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_SECONDARY, F1_0 ); #ifdef NETWORK if (Game_mode & GM_MULTI) { if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0); } #endif if (wait_for_rearm) Next_missile_fire_time = GameTime64 + REARM_TIME; else Next_missile_fire_time = 0; Global_missile_firing_count = 0; } else { if (wait_for_rearm) digi_play_sample_once( SOUND_ALREADY_SELECTED, F1_0 ); } Secondary_weapon = weapon_num; weapon_name = SECONDARY_WEAPON_NAMES(weapon_num); } if (print_message) HUD_init_message(HM_DEFAULT, "%s %s", weapon_name, TXT_SELECTED); } // ------------------------------------------------------------------------------------ // Select a weapon, primary or secondary. void do_weapon_select(int weapon_num, int secondary_flag) { //added on 10/9/98 by Victor Rachels to add laser cycle int oweapon = weapon_num; //end this section addition - Victor Rachels int weapon_status = player_has_weapon(weapon_num, secondary_flag); char *weapon_name; // do special hud msg. for picking registered weapon in shareware version. if (PCSharePig) if (weapon_num >= NUM_SHAREWARE_WEAPONS) { weapon_name = secondary_flag?SECONDARY_WEAPON_NAMES(weapon_num):PRIMARY_WEAPON_NAMES(weapon_num); HUD_init_message(HM_DEFAULT, "%s %s!", weapon_name,TXT_NOT_IN_SHAREWARE); digi_play_sample( SOUND_BAD_SELECTION, F1_0 ); return; } if (!secondary_flag) { if (weapon_num >= MAX_PRIMARY_WEAPONS) weapon_num = 0; weapon_name = PRIMARY_WEAPON_NAMES(weapon_num); if ((weapon_status & HAS_WEAPON_FLAG) == 0) { HUD_init_message(HM_DEFAULT, "%s %s!", TXT_DONT_HAVE, weapon_name); digi_play_sample( SOUND_BAD_SELECTION, F1_0 ); return; } else if ((weapon_status & HAS_AMMO_FLAG) == 0) { HUD_init_message(HM_DEFAULT, "%s %s!", TXT_DONT_HAVE_AMMO, weapon_name); digi_play_sample( SOUND_BAD_SELECTION, F1_0 ); return; } } else { weapon_name = SECONDARY_WEAPON_NAMES(weapon_num); if (weapon_status != HAS_ALL) { HUD_init_message(HM_DEFAULT, "%s %s%s",TXT_HAVE_NO, weapon_name, TXT_SX); digi_play_sample( SOUND_BAD_SELECTION, F1_0 ); return; } } weapon_num=oweapon; select_weapon(weapon_num, secondary_flag, 1, 1); } // ---------------------------------------------------------------------------------------- // Automatically select best available weapon if unable to fire current weapon. // Weapon type: 0==primary, 1==secondary void auto_select_weapon(int weapon_type) { int r; int cutpoint; int looped=0; if (weapon_type==0) { r = player_has_weapon(Primary_weapon, 0); if (r != HAS_ALL) { int cur_weapon; int try_again = 1; cur_weapon = POrderList(Primary_weapon); cutpoint = POrderList (255); while (try_again) { cur_weapon++; if (cur_weapon>=cutpoint) { if (looped) { HUD_init_message_literal(HM_DEFAULT, TXT_NO_PRIMARY); select_weapon(0, 0, 0, 1); try_again = 0; continue; } cur_weapon=0; looped=1; } if (cur_weapon==MAX_PRIMARY_WEAPONS) cur_weapon = 0; // Hack alert! Because the fusion uses 0 energy at the end (it's got the weird chargeup) // it looks like it takes 0 to fire, but it doesn't, so never auto-select. // if (PlayerCfg.PrimaryOrder[cur_weapon] == FUSION_INDEX) // continue; if (PlayerCfg.PrimaryOrder[cur_weapon] == Primary_weapon) { HUD_init_message_literal(HM_DEFAULT, TXT_NO_PRIMARY); select_weapon(0, 0, 0, 1); try_again = 0; // Tried all weapons! } else if (PlayerCfg.PrimaryOrder[cur_weapon]!=255 && player_has_weapon(PlayerCfg.PrimaryOrder[cur_weapon], 0) == HAS_ALL) { select_weapon(PlayerCfg.PrimaryOrder[cur_weapon], 0, 1, 1 ); try_again = 0; } } } } else { Assert(weapon_type==1); r = player_has_weapon(Secondary_weapon, 1); if (r != HAS_ALL) { int cur_weapon; int try_again = 1; cur_weapon = SOrderList(Secondary_weapon); cutpoint = SOrderList (255); while (try_again) { cur_weapon++; if (cur_weapon>=cutpoint) { if (looped) { HUD_init_message_literal(HM_DEFAULT, "No secondary weapons selected!"); try_again = 0; continue; } cur_weapon=0; looped=1; } if (cur_weapon==MAX_SECONDARY_WEAPONS) cur_weapon = 0; if (PlayerCfg.SecondaryOrder[cur_weapon] == Secondary_weapon) { HUD_init_message_literal(HM_DEFAULT, "No secondary weapons available!"); try_again = 0; // Tried all weapons! } else if (player_has_weapon(PlayerCfg.SecondaryOrder[cur_weapon], 1) == HAS_ALL) { select_weapon(PlayerCfg.SecondaryOrder[cur_weapon], 1, 1, 1 ); try_again = 0; } } } } } // --------------------------------------------------------------------- //called when one of these weapons is picked up //when you pick up a secondary, you always get the weapon & ammo for it // Returns true if powerup picked up, else returns false. int pick_up_secondary(int weapon_index,int count) { int max; int num_picked_up; int cutpoint; max = Secondary_ammo_max[weapon_index]; if (Players[Player_num].secondary_ammo[weapon_index] >= max) { HUD_init_message(HM_DEFAULT|HM_REDUNDANT|HM_MAYDUPL, "%s %i %ss!", TXT_ALREADY_HAVE, Players[Player_num].secondary_ammo[weapon_index],SECONDARY_WEAPON_NAMES(weapon_index)); return 0; } Players[Player_num].secondary_weapon_flags |= (1< max) { num_picked_up = count - (Players[Player_num].secondary_ammo[weapon_index] - max); Players[Player_num].secondary_ammo[weapon_index] = max; } if (Players[Player_num].secondary_ammo[weapon_index] == count) // only autoselect if player didn't have any { cutpoint=SOrderList (255); if (((Controls.fire_secondary_state && PlayerCfg.NoFireAutoselect)?0:1) && SOrderList (weapon_index)1) { PALETTE_FLASH_ADD(15,15,15); HUD_init_message(HM_DEFAULT, "%d %s%s",num_picked_up,SECONDARY_WEAPON_NAMES(weapon_index), TXT_SX); } else { PALETTE_FLASH_ADD(10,10,10); HUD_init_message(HM_DEFAULT, "%s!",SECONDARY_WEAPON_NAMES(weapon_index)); } return 1; } void ReorderPrimary () { newmenu_item m[MAX_PRIMARY_WEAPONS+1]; int i; for (i=0;i max) { ammo_count += (max - Players[Player_num].primary_ammo[weapon_index]); Players[Player_num].primary_ammo[weapon_index] = max; } cutpoint=POrderList (255); if (((Controls.fire_primary_state && PlayerCfg.NoFireAutoselect)?0:1) && Players[Player_num].primary_weapon_flags&(1<Primary_weapon && old_ammo==0 && POrderList(weapon_index)weapon_flags & WEAPON_FLAG is set, then the player has this weapon #define HAS_LASER_FLAG HAS_FLAG(LASER_INDEX) #define HAS_VULCAN_FLAG HAS_FLAG(VULCAN_INDEX) #define HAS_SPREADFIRE_FLAG HAS_FLAG(SPREADFIRE_INDEX) #define HAS_PLASMA_FLAG HAS_FLAG(PLASMA_INDEX) #define HAS_FUSION_FLAG HAS_FLAG(FUSION_INDEX) #define HAS_CONCUSSION_FLAG HAS_FLAG(CONCUSSION_INDEX) #define HAS_SMART_FLAG HAS_FLAG(SMART_INDEX) #define HAS_MEGA_FLAG HAS_FLAG(MEGA_INDEX) #define CLASS_PRIMARY 0 #define CLASS_SECONDARY 1 #define LASER_INDEX 0 #define VULCAN_INDEX 1 #define SPREADFIRE_INDEX 2 #define PLASMA_INDEX 3 #define FUSION_INDEX 4 #define CONCUSSION_INDEX 0 #define HOMING_INDEX 1 #define PROXIMITY_INDEX 2 #define SMART_INDEX 3 #define MEGA_INDEX 4 #define NUM_SHAREWARE_WEAPONS 3 //in shareware, old get first 3 of each #define VULCAN_AMMO_SCALE (0x198300/2) //multiply ammo by this before displaying extern weapon_info Weapon_info[]; extern int N_weapon_types; extern void do_weapon_select(int weapon_num, int secondary_flag); extern sbyte Primary_weapon, Secondary_weapon; extern const ubyte Primary_weapon_to_weapon_info[MAX_PRIMARY_WEAPONS]; extern const ubyte Secondary_weapon_to_weapon_info[MAX_SECONDARY_WEAPONS]; //for each primary weapon, what kind of powerup gives weapon extern const ubyte Primary_weapon_to_powerup[MAX_SECONDARY_WEAPONS]; //for each Secondary weapon, what kind of powerup gives weapon extern const ubyte Secondary_weapon_to_powerup[MAX_SECONDARY_WEAPONS]; extern void auto_select_weapon(int weapon_type); //parm is primary or secondary extern void select_weapon(int weapon_num, int secondary_flag, int print_message,int wait_for_rearm); extern const int Primary_ammo_max[MAX_PRIMARY_WEAPONS]; extern const ubyte Secondary_ammo_max[MAX_PRIMARY_WEAPONS]; #define HAS_WEAPON_FLAG 1 #define HAS_ENERGY_FLAG 2 #define HAS_AMMO_FLAG 4 #define HAS_ALL (HAS_WEAPON_FLAG|HAS_ENERGY_FLAG|HAS_AMMO_FLAG) // ------------------------------------------------------------------------------------ // Return: // Bits set: // HAS_WEAPON_FLAG // HAS_ENERGY_FLAG // HAS_AMMO_FLAG extern int player_has_weapon(int weapon_num, int secondary_flag); //called when one of these weapons is picked up //when you pick up a secondary, you always get the weapon & ammo for it int pick_up_secondary(int weapon_index,int count); //called when a primary weapon is picked up //returns true if actually picked up int pick_up_primary(int weapon_index); //called when ammo (for the vulcan cannon) is picked up int pick_up_ammo(int class_flag,int weapon_index,int ammo_count); extern void maybe_select_primary(int weapon_index); extern void maybe_select_secondary(int weapon_index); /* * reads n weapon_info structs from a PHYSFS_file */ extern int weapon_info_read_n(weapon_info *wi, int n, PHYSFS_file *fp, int file_version); //return which bomb will be dropped next time the bomb key is pressed static inline int which_bomb(void) { return PROXIMITY_INDEX; } #endif dxx-rebirth-0.58.1-d1x/maths/000077500000000000000000000000001217717257200156665ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/maths/fixc.c000066400000000000000000000154411217717257200167700ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * C version of fixed point library * */ #include #include #include "dxxerror.h" #include "maths.h" //negate a quad void fixquadnegate(quadint *q) { q->low = 0 - q->low; q->high = 0 - q->high - (q->low != 0); } //multiply two ints & add 64-bit result to 64-bit sum void fixmulaccum(quadint *q,fix a,fix b) { u_int32_t aa,bb; u_int32_t ah,al,bh,bl; u_int32_t t,c=0,old; int neg; neg = ((a^b) < 0); aa = labs(a); bb = labs(b); ah = aa>>16; al = aa&0xffff; bh = bb>>16; bl = bb&0xffff; t = ah*bl + bh*al; if (neg) fixquadnegate(q); old = q->low; q->low += al*bl; if (q->low < old) q->high++; old = q->low; q->low += (t<<16); if (q->low < old) q->high++; q->high += ah*bh + (t>>16) + c; if (neg) fixquadnegate(q); } //extract a fix from a quad product fix fixquadadjust(quadint *q) { return (q->high<<16) + (q->low>>16); } #define EPSILON (F1_0/100) fix fixmul(fix a, fix b) { return (fix)((((fix64) a) * b) / 65536); } fix64 fixmul64(fix a, fix b) { return (fix64)((((fix64) a) * b) / 65536); } fix fixdiv(fix a, fix b) { return b ? (fix)((((fix64)a) *65536)/b) : 1; } fix fixmuldiv(fix a, fix b, fix c) { return c ? (fix)((((fix64)a)*b)/c) : 1; } //given cos & sin of an angle, return that angle. //parms need not be normalized, that is, the ratio of the parms cos/sin must //equal the ratio of the actual cos & sin for the result angle, but the parms //need not be the actual cos & sin. //NOTE: this is different from the standard C atan2, since it is left-handed. fixang fix_atan2(fix cos,fix sin) { double d, dsin, dcos; fixang t; //Assert(!(cos==0 && sin==0)); //find smaller of two dsin = (double)sin; dcos = (double)cos; d = sqrt((dsin * dsin) + (dcos * dcos)); if (d==0.0) return 0; if (labs(sin) < labs(cos)) { //sin is smaller, use arcsin t = fix_asin((fix)((dsin / d) * 65536.0)); if (cos<0) t = 0x8000 - t; return t; } else { t = fix_acos((fix)((dcos / d) * 65536.0)); if (sin<0) t = -t; return t; } } int32_t fixdivquadlong(u_int32_t nl,u_int32_t nh,u_int32_t d) { int64_t n = (int64_t)nl | (((int64_t)nh) << 32 ); return (signed int) (n / ((int64_t)d)); } unsigned int fixdivquadlongu(uint nl, uint nh, uint d) { u_int64_t n = (u_int64_t)nl | (((u_int64_t)nh) << 32 ); return (unsigned int) (n / ((u_int64_t)d)); } u_int32_t quad_sqrt(u_int32_t low,int32_t high) { int i, cnt; u_int32_t r,old_r,t; quadint tq; if (high<0) return 0; if (high==0 && (int32_t)low>=0) return long_sqrt((int32_t)low); if (high & 0xff000000) { cnt=12+16; i = high >> 24; } else if (high & 0xff0000) { cnt=8+16; i = high >> 16; } else if (high & 0xff00) { cnt=4+16; i = high >> 8; } else { cnt=0+16; i = high; } r = guess_table[i]<>cnt)&0xff]<>8)&0xff; f = a&0xff; ss = sincos_table[i]; if (s) *s = (ss + (((sincos_table[i+1] - ss) * f)>>8))<<2; cc = sincos_table[i+64]; if (c) *c = (cc + (((sincos_table[i+64+1] - cc) * f)>>8))<<2; } //compute sine and cosine of an angle, filling in the variables //either of the pointers can be NULL //no interpolation void fix_fastsincos(fix a,fix *s,fix *c) { int i; i = (a>>8)&0xff; if (s) *s = sincos_table[i] << 2; if (c) *c = sincos_table[i+64] << 2; } //compute inverse sine fixang fix_asin(fix v) { fix vv; int i,f,aa; vv = labs(v); if (vv >= f1_0) //check for out of range return 0x4000; i = (vv>>8)&0xff; f = vv&0xff; aa = asin_table[i]; aa = aa + (((asin_table[i+1] - aa) * f)>>8); if (v < 0) aa = -aa; return aa; } //compute inverse cosine fixang fix_acos(fix v) { fix vv; int i,f,aa; vv = labs(v); if (vv >= f1_0) //check for out of range return 0; i = (vv>>8)&0xff; f = vv&0xff; aa = acos_table[i]; aa = aa + (((acos_table[i+1] - aa) * f)>>8); if (v < 0) aa = 0x8000 - aa; return aa; } #define TABLE_SIZE 1024 //for passed value a, returns 1/sqrt(a) fix fix_isqrt( fix a ) { int i, b = a; int cnt = 0; int r; if ( a == 0 ) return 0; while( b >= TABLE_SIZE ) { b >>= 1; cnt++; } r = isqrt_guess_table[b] >> ((cnt+1)/2); for (i=0; i<3; i++ ) { int old_r = r; r = fixmul( ( (3*65536) - fixmul(fixmul(r,r),a) ), r) / 2; if ( old_r >= r ) return (r+old_r)/2; } return r; } dxx-rebirth-0.58.1-d1x/maths/rand.c000066400000000000000000000006721217717257200167630ustar00rootroot00000000000000// Descent random number stuff... // rand has different ranges on different machines... #include #include "maths.h" #ifdef NO_WATCOM_RAND void d_srand(unsigned int seed) { srand(seed); } int d_rand() { return rand() & 0x7fff; } #else static unsigned int d_rand_seed; int d_rand() { return ((d_rand_seed = d_rand_seed * 0x41c64e6d + 0x3039) >> 16) & 0x7fff; } void d_srand(unsigned int seed) { d_rand_seed = seed; } #endif dxx-rebirth-0.58.1-d1x/maths/tables.c000066400000000000000000000366451217717257200173220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * C version of fixed point library * */ #include "maths.h" const ubyte guess_table[] = { 1, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 }; const short sincos_table[] = { 0, 402, 804, 1205, 1606, 2006, 2404, 2801, 3196, 3590, 3981, 4370, 4756, 5139, 5520, 5897, 6270, 6639, 7005, 7366, 7723, 8076, 8423, 8765, 9102, 9434, 9760, 10080, 10394, 10702, 11003, 11297, 11585, 11866, 12140, 12406, 12665, 12916, 13160, 13395, 13623, 13842, 14053, 14256, 14449, 14635, 14811, 14978, 15137, 15286, 15426, 15557, 15679, 15791, 15893, 15986, 16069, 16143, 16207, 16261, 16305, 16340, 16364, 16379, // cos_table 16384, 16379, 16364, 16340, 16305, 16261, 16207, 16143, 16069, 15986, 15893, 15791, 15679, 15557, 15426, 15286, 15137, 14978, 14811, 14635, 14449, 14256, 14053, 13842, 13623, 13395, 13160, 12916, 12665, 12406, 12140, 11866, 11585, 11297, 11003, 10702, 10394, 10080, 9760, 9434, 9102, 8765, 8423, 8076, 7723, 7366, 7005, 6639, 6270, 5897, 5520, 5139, 4756, 4370, 3981, 3590, 3196, 2801, 2404, 2006, 1606, 1205, 804, 402, 0, -402, -804, -1205, -1606, -2006, -2404, -2801, -3196, -3590, -3981, -4370, -4756, -5139, -5520, -5897, -6270, -6639, -7005, -7366, -7723, -8076, -8423, -8765, -9102, -9434, -9760, -10080, -10394, -10702, -11003, -11297, -11585, -11866, -12140, -12406, -12665, -12916, -13160, -13395, -13623, -13842, -14053, -14256, -14449, -14635, -14811, -14978, -15137, -15286, -15426, -15557, -15679, -15791, -15893, -15986, -16069, -16143, -16207, -16261, -16305, -16340, -16364, -16379, -16384, -16379, -16364, -16340, -16305, -16261, -16207, -16143, -16069, -15986, -15893, -15791, -15679, -15557, -15426, -15286, -15137, -14978, -14811, -14635, -14449, -14256, -14053, -13842, -13623, -13395, -13160, -12916, -12665, -12406, -12140, -11866, -11585, -11297, -11003, -10702, -10394, -10080, -9760, -9434, -9102, -8765, -8423, -8076, -7723, -7366, -7005, -6639, -6270, -5897, -5520, -5139, -4756, -4370, -3981, -3590, -3196, -2801, -2404, -2006, -1606, -1205, -804, -402, 0, 402, 804, 1205, 1606, 2006, 2404, 2801, 3196, 3590, 3981, 4370, 4756, 5139, 5520, 5897, 6270, 6639, 7005, 7366, 7723, 8076, 8423, 8765, 9102, 9434, 9760, 10080, 10394, 10702, 11003, 11297, 11585, 11866, 12140, 12406, 12665, 12916, 13160, 13395, 13623, 13842, 14053, 14256, 14449, 14635, 14811, 14978, 15137, 15286, 15426, 15557, 15679, 15791, 15893, 15986, 16069, 16143, 16207, 16261, 16305, 16340, 16364, 16379, 16384 }; const ushort asin_table[] = { 0, 41, 81, 122, 163, 204, 244, 285, 326, 367, 408, 448, 489, 530, 571, 612, 652, 693, 734, 775, 816, 857, 897, 938, 979, 1020, 1061, 1102, 1143, 1184, 1225, 1266, 1307, 1348, 1389, 1431, 1472, 1513, 1554, 1595, 1636, 1678, 1719, 1760, 1802, 1843, 1884, 1926, 1967, 2009, 2050, 2092, 2134, 2175, 2217, 2259, 2300, 2342, 2384, 2426, 2468, 2510, 2551, 2593, 2636, 2678, 2720, 2762, 2804, 2847, 2889, 2931, 2974, 3016, 3059, 3101, 3144, 3187, 3229, 3272, 3315, 3358, 3401, 3444, 3487, 3530, 3573, 3617, 3660, 3704, 3747, 3791, 3834, 3878, 3922, 3965, 4009, 4053, 4097, 4142, 4186, 4230, 4275, 4319, 4364, 4408, 4453, 4498, 4543, 4588, 4633, 4678, 4723, 4768, 4814, 4859, 4905, 4951, 4997, 5043, 5089, 5135, 5181, 5228, 5274, 5321, 5367, 5414, 5461, 5508, 5556, 5603, 5651, 5698, 5746, 5794, 5842, 5890, 5938, 5987, 6035, 6084, 6133, 6182, 6231, 6281, 6330, 6380, 6430, 6480, 6530, 6580, 6631, 6681, 6732, 6783, 6835, 6886, 6938, 6990, 7042, 7094, 7147, 7199, 7252, 7306, 7359, 7413, 7466, 7521, 7575, 7630, 7684, 7740, 7795, 7851, 7907, 7963, 8019, 8076, 8133, 8191, 8249, 8307, 8365, 8424, 8483, 8543, 8602, 8663, 8723, 8784, 8846, 8907, 8970, 9032, 9095, 9159, 9223, 9288, 9353, 9418, 9484, 9551, 9618, 9686, 9754, 9823, 9892, 9963, 10034, 10105, 10177, 10251, 10324, 10399, 10475, 10551, 10628, 10706, 10785, 10866, 10947, 11029, 11113, 11198, 11284, 11371, 11460, 11550, 11642, 11736, 11831, 11929, 12028, 12130, 12234, 12340, 12449, 12561, 12677, 12796, 12919, 13046, 13178, 13315, 13459, 13610, 13770, 13939, 14121, 14319, 14538, 14786, 15079, 15462, 16384, 16384 // extra for when exactly 1 }; const ushort acos_table[] = { 16384, 16343, 16303, 16262, 16221, 16180, 16140, 16099, 16058, 16017, 15976, 15936, 15895, 15854, 15813, 15772, 15732, 15691, 15650, 15609, 15568, 15527, 15487, 15446, 15405, 15364, 15323, 15282, 15241, 15200, 15159, 15118, 15077, 15036, 14995, 14953, 14912, 14871, 14830, 14789, 14748, 14706, 14665, 14624, 14582, 14541, 14500, 14458, 14417, 14375, 14334, 14292, 14250, 14209, 14167, 14125, 14084, 14042, 14000, 13958, 13916, 13874, 13833, 13791, 13748, 13706, 13664, 13622, 13580, 13537, 13495, 13453, 13410, 13368, 13325, 13283, 13240, 13197, 13155, 13112, 13069, 13026, 12983, 12940, 12897, 12854, 12811, 12767, 12724, 12680, 12637, 12593, 12550, 12506, 12462, 12419, 12375, 12331, 12287, 12242, 12198, 12154, 12109, 12065, 12020, 11976, 11931, 11886, 11841, 11796, 11751, 11706, 11661, 11616, 11570, 11525, 11479, 11433, 11387, 11341, 11295, 11249, 11203, 11156, 11110, 11063, 11017, 10970, 10923, 10876, 10828, 10781, 10733, 10686, 10638, 10590, 10542, 10494, 10446, 10397, 10349, 10300, 10251, 10202, 10153, 10103, 10054, 10004, 9954, 9904, 9854, 9804, 9753, 9703, 9652, 9601, 9549, 9498, 9446, 9394, 9342, 9290, 9237, 9185, 9132, 9078, 9025, 8971, 8918, 8863, 8809, 8754, 8700, 8644, 8589, 8533, 8477, 8421, 8365, 8308, 8251, 8193, 8135, 8077, 8019, 7960, 7901, 7841, 7782, 7721, 7661, 7600, 7538, 7477, 7414, 7352, 7289, 7225, 7161, 7096, 7031, 6966, 6900, 6833, 6766, 6698, 6630, 6561, 6492, 6421, 6350, 6279, 6207, 6133, 6060, 5985, 5909, 5833, 5756, 5678, 5599, 5518, 5437, 5355, 5271, 5186, 5100, 5013, 4924, 4834, 4742, 4648, 4553, 4455, 4356, 4254, 4150, 4044, 3935, 3823, 3707, 3588, 3465, 3338, 3206, 3069, 2925, 2774, 2614, 2445, 2263, 2065, 1846, 1598, 1305, 922, 0, 0 // extra for when exactly 1 }; const fix isqrt_guess_table[] = { // 0, 0x80000000, 16777216,11863283,9686330,8388608,7502999,6849269,6341191, 5931641,5592405,5305421,5058520,4843165,4653162,4483899,4331858, 4194304,4069072,3954427,3848957,3751499,3661088,3576914,3498291, 3424634,3355443,3290282,3228776,3170595,3115450,3063086,3013276, 2965820,2920538,2877268,2835867,2796202,2758157,2721623,2686504, 2652710,2620160,2588780,2558501,2529260,2500999,2473665,2447208, 2421582,2396745,2372656,2349280,2326581,2304527,2283089,2262239, 2241949,2222196,2202956,2184207,2165929,2148102,2130708,2113730, 2097152,2080957,2065132,2049663,2034536,2019739,2005260,1991089, 1977213,1963624,1950311,1937266,1924478,1911941,1899645,1887584, 1875749,1864135,1852733,1841538,1830544,1819744,1809133,1798706, 1788457,1778381,1768473,1758730,1749145,1739716,1730437,1721306, 1712317,1703468,1694754,1686173,1677721,1669395,1661191,1653108, 1645141,1637288,1629547,1621914,1614388,1606965,1599644,1592422, 1585297,1578267,1571330,1564483,1557725,1551054,1544467,1537964, 1531543,1525201,1518937,1512750,1506638,1500599,1494633,1488737, 1482910,1477151,1471459,1465832,1460269,1454769,1449330,1443952, 1438634,1433374,1428171,1423024,1417933,1412896,1407912,1402981, 1398101,1393271,1388492,1383761,1379078,1374443,1369853,1365310, 1360811,1356357,1351946,1347578,1343252,1338967,1334723,1330519, 1326355,1322229,1318142,1314092,1310080,1306104,1302164,1298259, 1294390,1290555,1286753,1282985,1279250,1275548,1271877,1268238, 1264630,1261052,1257505,1253987,1250499,1247040,1243609,1240207, 1236832,1233485,1230165,1226871,1223604,1220362,1217147,1213956, 1210791,1207650,1204533,1201441,1198372,1195327,1192304,1189305, 1186328,1183373,1180440,1177529,1174640,1171771,1168924,1166097, 1163290,1160504,1157737,1154991,1152263,1149555,1146866,1144196, 1141544,1138911,1136296,1133699,1131119,1128557,1126013,1123485, 1120974,1118481,1116003,1113542,1111098,1108669,1106256,1103859, 1101478,1099111,1096760,1094424,1092103,1089797,1087505,1085227, 1082964,1080715,1078480,1076258,1074051,1071857,1069676,1067508, 1065354,1063212,1061084,1058968,1056865,1054774,1052696,1050630, 1048576,1046533,1044503,1042485,1040478,1038483,1036499,1034527, 1032566,1030616,1028677,1026748,1024831,1022924,1021028,1019143, 1017268,1015403,1013548,1011704,1009869,1008045,1006230,1004425, 1002630,1000844,999068,997301,995544,993796,992057,990327, 988606,986895,985192,983497,981812,980135,978467,976807, 975155,973512,971878,970251,968633,967022,965420,963825, 962239,960660,959089,957526,955970,954422,952881,951348, 949822,948304,946793,945289,943792,942302,940819,939343, 937874,936412,934957,933509,932067,930632,929204,927782, 926366,924957,923555,922159,920769,919385,918008,916637, 915272,913913,912560,911213,909872,908537,907207,905884, 904566,903254,901948,900648,899353,898063,896779,895501, 894228,892961,891698,890442,889190,887944,886703,885467, 884236,883011,881790,880575,879365,878159,876959,875763, 874572,873386,872205,871029,869858,868691,867529,866371, 865218,864070,862926,861787,860653,859522,858397,857275, 856158,855046,853937,852833,851734,850638,849547,848460, 847377,846298,845223,844153,843086,842024,840965,839911, 838860,837814,836771,835732,834697,833666,832639,831615, 830595,829579,828567,827559,826554,825552,824555,823561, 822570,821583,820600,819620,818644,817671,816702,815736, 814773,813814,812858,811906,810957,810011,809069,808130, 807194,806261,805332,804405,803482,802563,801646,800732, 799822,798915,798010,797109,796211,795316,794424,793535, 792648,791765,790885,790008,789133,788262,787393,786528, 785665,784805,783947,783093,782241,781392,780546,779703, 778862,778024,777189,776356,775527,774699,773875,773053, 772233,771417,770603,769791,768982,768175,767371,766570, 765771,764975,764181,763389,762600,761814,761029,760248, 759468,758691,757917,757145,756375,755607,754842,754079, 753319,752560,751805,751051,750299,749550,748803,748059, 747316,746576,745838,745102,744368,743637,742907,742180, 741455,740732,740011,739292,738575,737861,737148,736438, 735729,735023,734318,733616,732916,732217,731521,730827, 730134,729444,728755,728069,727384,726701,726021,725342, 724665,723990,723317,722645,721976,721308,720643,719979, 719317,718656,717998,717341,716687,716034,715382,714733, 714085,713439,712795,712153,711512,710873,710236,709600, 708966,708334,707704,707075,706448,705822,705198,704576, 703956,703337,702720,702104,701490,700878,700267,699658, 699050,698444,697840,697237,696635,696036,695437,694841, 694246,693652,693060,692469,691880,691293,690707,690122, 689539,688957,688377,687798,687221,686645,686071,685498, 684926,684356,683788,683221,682655,682090,681527,680966, 680405,679847,679289,678733,678178,677625,677073,676522, 675973,675425,674878,674333,673789,673246,672705,672164, 671626,671088,670552,670017,669483,668951,668420,667890, 667361,666834,666308,665783,665259,664737,664216,663696, 663177,662660,662143,661628,661114,660602,660090,659580, 659071,658563,658056,657550,657046,656543,656041,655540, 655040,654541,654043,653547,653052,652558,652065,651573, 651082,650592,650103,649616,649129,648644,648160,647677, 647195,646714,646234,645755,645277,644800,644325,643850, 643376,642904,642432,641962,641492,641024,640557,640090, 639625,639161,638697,638235,637774,637313,636854,636396, 635938,635482,635026,634572,634119,633666,633215,632764, 632315,631866,631418,630972,630526,630081,629637,629194, 628752,628311,627871,627432,626993,626556,626120,625684, 625249,624816,624383,623951,623520,623090,622660,622232, 621804,621378,620952,620527,620103,619680,619258,618836, 618416,617996,617577,617159,616742,616326,615910,615496, 615082,614669,614257,613846,613435,613026,612617,612209, 611802,611395,610990,610585,610181,609778,609375,608974, 608573,608173,607774,607375,606978,606581,606185,605790, 605395,605001,604608,604216,603825,603434,603044,602655, 602266,601879,601492,601106,600720,600335,599952,599568, 599186,598804,598423,598043,597663,597284,596906,596529, 596152,595776,595401,595026,594652,594279,593907,593535, 593164,592793,592424,592055,591686,591319,590952,590585, 590220,589855,589491,589127,588764,588402,588041,587680, 587320,586960,586601,586243,585885,585528,585172,584816, 584462,584107,583754,583400,583048,582696,582345,581995, 581645,581296,580947,580599,580252,579905,579559,579213, 578868,578524,578181,577838,577495,577153,576812,576471, 576131,575792,575453,575115,574777,574440,574104,573768, 573433,573098,572764,572431,572098,571765,571434,571103, 570772,570442,570113,569784,569455,569128,568800,568474, 568148,567822,567497,567173,566849,566526,566203,565881, 565559,565238,564918,564598,564278,563959,563641,563323, 563006,562689,562373,562057,561742,561428,561114,560800, 560487,560174,559862,559551,559240,558930,558620,558310, 558001,557693,557385,557078,556771,556465,556159,555853, 555549,555244,554940,554637,554334,554032,553730,553429, 553128,552828,552528,552228,551929,551631,551333,551036, 550739,550442,550146,549851,549555,549261,548967,548673, 548380,548087,547795,547503,547212,546921,546631,546341, 546051,545762,545474,545186,544898,544611,544324,544038, 543752,543467,543182,542897,542613,542330,542047,541764, 541482,541200,540919,540638,540357,540077,539798,539518, 539240,538961,538683,538406,538129,537852,537576,537300, 537025,536750,536476,536202,535928,535655,535382,535110, 534838,534566,534295,534024,533754,533484,533214,532945, 532677,532408,532140,531873,531606,531339,531073,530807, 530542,530277,530012,529748,529484,529220,528957,528694, 528432,528170,527909,527648,527387,527126,526866,526607, 526348,526089,525830,525572,525315,525057,524800,524544 }; dxx-rebirth-0.58.1-d1x/maths/vecmat.c000066400000000000000000000517121217717257200173170ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * C version of vecmat library * */ #include #include // for sqrt #include "maths.h" #include "vecmat.h" #include "dxxerror.h" //#define USE_ISQRT 1 vms_vector vmd_zero_vector = ZERO_VECTOR; vms_matrix vmd_identity_matrix = IDENTITY_MATRIX; //adds two vectors, fills in dest, returns ptr to dest //ok for dest to equal either source, but should use vm_vec_add2() if so vms_vector *vm_vec_add(vms_vector *dest,const vms_vector *src0,const vms_vector *src1) { dest->x = src0->x + src1->x; dest->y = src0->y + src1->y; dest->z = src0->z + src1->z; return dest; } //subs two vectors, fills in dest, returns ptr to dest //ok for dest to equal either source, but should use vm_vec_sub2() if so vms_vector *vm_vec_sub(vms_vector *dest,const vms_vector *src0,const vms_vector *src1) { dest->x = src0->x - src1->x; dest->y = src0->y - src1->y; dest->z = src0->z - src1->z; return dest; } //adds one vector to another. returns ptr to dest //dest can equal source vms_vector *vm_vec_add2(vms_vector *dest,const vms_vector *src) { dest->x += src->x; dest->y += src->y; dest->z += src->z; return dest; } //subs one vector from another, returns ptr to dest //dest can equal source vms_vector *vm_vec_sub2(vms_vector *dest,const vms_vector *src) { dest->x -= src->x; dest->y -= src->y; dest->z -= src->z; return dest; } //averages two vectors. returns ptr to dest //dest can equal either source vms_vector *vm_vec_avg(vms_vector *dest,const vms_vector *src0,const vms_vector *src1) { dest->x = (src0->x + src1->x)/2; dest->y = (src0->y + src1->y)/2; dest->z = (src0->z + src1->z)/2; return dest; } //averages four vectors. returns ptr to dest //dest can equal any source vms_vector *vm_vec_avg4(vms_vector *dest,const vms_vector *src0,const vms_vector *src1,const vms_vector *src2,const vms_vector *src3) { dest->x = (src0->x + src1->x + src2->x + src3->x)/4; dest->y = (src0->y + src1->y + src2->y + src3->y)/4; dest->z = (src0->z + src1->z + src2->z + src3->z)/4; return dest; } //scales a vector in place. returns ptr to vector vms_vector *vm_vec_scale(vms_vector *dest,fix s) { dest->x = fixmul(dest->x,s); dest->y = fixmul(dest->y,s); dest->z = fixmul(dest->z,s); return dest; } //scales and copies a vector. returns ptr to dest vms_vector *vm_vec_copy_scale(vms_vector *dest,const vms_vector *src,fix s) { dest->x = fixmul(src->x,s); dest->y = fixmul(src->y,s); dest->z = fixmul(src->z,s); return dest; } //scales a vector, adds it to another, and stores in a 3rd vector //dest = src1 + k * src2 vms_vector *vm_vec_scale_add(vms_vector *dest,const vms_vector *src1,const vms_vector *src2,fix k) { dest->x = src1->x + fixmul(src2->x,k); dest->y = src1->y + fixmul(src2->y,k); dest->z = src1->z + fixmul(src2->z,k); return dest; } //scales a vector and adds it to another //dest += k * src vms_vector *vm_vec_scale_add2(vms_vector *dest,const vms_vector *src,fix k) { dest->x += fixmul(src->x,k); dest->y += fixmul(src->y,k); dest->z += fixmul(src->z,k); return dest; } //scales a vector in place, taking n/d for scale. returns ptr to vector //dest *= n/d vms_vector *vm_vec_scale2(vms_vector *dest,fix n,fix d) { #if 1 // DPH: Kludge: this was overflowing a lot, so I made it use the FPU. float nd; nd = f2fl(n) / f2fl(d); dest->x = fl2f( f2fl(dest->x) * nd); dest->y = fl2f( f2fl(dest->y) * nd); dest->z = fl2f( f2fl(dest->z) * nd); #else dest->x = fixmuldiv(dest->x,n,d); dest->y = fixmuldiv(dest->y,n,d); dest->z = fixmuldiv(dest->z,n,d); #endif return dest; } fix vm_vec_dotprod(const vms_vector *v0,const vms_vector *v1) { #if 0 quadint q; q.low = q.high = 0; fixmulaccum(&q,v0->x,v1->x); fixmulaccum(&q,v0->y,v1->y); fixmulaccum(&q,v0->z,v1->z); return fixquadadjust(&q); #else long long p = (long long) v0->x * v1->x + (long long) v0->y * v1->y + (long long) v0->z * v1->z; /* Convert back to fix and return. */ return p >> 16; #endif } fix vm_vec_dot3(fix x,fix y,fix z,vms_vector *v) { #if 0 quadint q; q.low = q.high = 0; fixmulaccum(&q,x,v->x); fixmulaccum(&q,y,v->y); fixmulaccum(&q,z,v->z); return fixquadadjust(&q); #else long long p = (long long) x * v->x + (long long) y * v->y + (long long) z * v->z; /* Convert back to fix and return. */ return p >> 16; #endif } //returns magnitude of a vector fix vm_vec_mag(vms_vector *v) { quadint q; q.low = q.high = 0; fixmulaccum(&q,v->x,v->x); fixmulaccum(&q,v->y,v->y); fixmulaccum(&q,v->z,v->z); return quad_sqrt(q.low,q.high); } //computes the distance between two points. (does sub and mag) fix vm_vec_dist(const vms_vector *v0,const vms_vector *v1) { vms_vector t; vm_vec_sub(&t,v0,v1); return vm_vec_mag(&t); } //computes an approximation of the magnitude of the vector //uses dist = largest + next_largest*3/8 + smallest*3/16 fix vm_vec_mag_quick(vms_vector *v) { fix a,b,c,bc; a = labs(v->x); b = labs(v->y); c = labs(v->z); if (a < b) { fix t=a; a=b; b=t; } if (b < c) { fix t=b; b=c; c=t; if (a < b) { fix t=a; a=b; b=t; } } bc = (b>>2) + (c>>3); return a + bc + (bc>>1); } //computes an approximation of the distance between two points. //uses dist = largest + next_largest*3/8 + smallest*3/16 fix vm_vec_dist_quick(vms_vector *v0,vms_vector *v1) { vms_vector t; vm_vec_sub(&t,v0,v1); return vm_vec_mag_quick(&t); } //normalize a vector. returns mag of source vec fix vm_vec_copy_normalize(vms_vector *dest,vms_vector *src) { fix m; m = vm_vec_mag(src); if (m > 0) { dest->x = fixdiv(src->x,m); dest->y = fixdiv(src->y,m); dest->z = fixdiv(src->z,m); } return m; } //normalize a vector. returns mag of source vec fix vm_vec_normalize(vms_vector *v) { return vm_vec_copy_normalize(v,v); } #ifndef USE_ISQRT //normalize a vector. returns mag of source vec. uses approx mag fix vm_vec_copy_normalize_quick(vms_vector *dest,vms_vector *src) { fix m; m = vm_vec_mag_quick(src); if (m > 0) { dest->x = fixdiv(src->x,m); dest->y = fixdiv(src->y,m); dest->z = fixdiv(src->z,m); } return m; } #else //these routines use an approximation for 1/sqrt //returns approximation of 1/magnitude of a vector fix vm_vec_imag(vms_vector *v) { quadint q; q.low = q.high = 0; fixmulaccum(&q,v->x,v->x); fixmulaccum(&q,v->y,v->y); fixmulaccum(&q,v->z,v->z); if (q.high==0) return fix_isqrt(fixquadadjust(&q)); else if (q.high >= 0x800000) { return (fix_isqrt(q.high) >> 8); } else return (fix_isqrt((q.high<<8) + (q.low>>24)) >> 4); } //normalize a vector. returns 1/mag of source vec. uses approx 1/mag fix vm_vec_copy_normalize_quick(vms_vector *dest,vms_vector *src) { fix im; im = vm_vec_imag(src); dest->x = fixmul(src->x,im); dest->y = fixmul(src->y,im); dest->z = fixmul(src->z,im); return im; } #endif //normalize a vector. returns 1/mag of source vec. uses approx 1/mag fix vm_vec_normalize_quick(vms_vector *v) { return vm_vec_copy_normalize_quick(v,v); } //return the normalized direction vector between two points //dest = normalized(end - start). Returns 1/mag of direction vector //NOTE: the order of the parameters matches the vector subtraction fix vm_vec_normalized_dir_quick(vms_vector *dest,vms_vector *end,vms_vector *start) { vm_vec_sub(dest,end,start); return vm_vec_normalize_quick(dest); } //return the normalized direction vector between two points //dest = normalized(end - start). Returns mag of direction vector //NOTE: the order of the parameters matches the vector subtraction fix vm_vec_normalized_dir(vms_vector *dest,vms_vector *end,vms_vector *start) { vm_vec_sub(dest,end,start); return vm_vec_normalize(dest); } //computes surface normal from three points. result is normalized //returns ptr to dest //dest CANNOT equal either source vms_vector *vm_vec_normal(vms_vector *dest,vms_vector *p0,vms_vector *p1,vms_vector *p2) { vm_vec_perp(dest,p0,p1,p2); vm_vec_normalize(dest); return dest; } //make sure a vector is reasonably sized to go into a cross product void check_vec(vms_vector *v) { fix check; int cnt = 0; check = labs(v->x) | labs(v->y) | labs(v->z); if (check == 0) return; if (check & 0xfffc0000) { //too big while (check & 0xfff00000) { cnt += 4; check >>= 4; } while (check & 0xfffc0000) { cnt += 2; check >>= 2; } v->x >>= cnt; v->y >>= cnt; v->z >>= cnt; } else //maybe too small if ((check & 0xffff8000) == 0) { //yep, too small while ((check & 0xfffff000) == 0) { cnt += 4; check <<= 4; } while ((check & 0xffff8000) == 0) { cnt += 2; check <<= 2; } v->x >>= cnt; v->y >>= cnt; v->z >>= cnt; } } //computes cross product of two vectors. //Note: this magnitude of the resultant vector is the //product of the magnitudes of the two source vectors. This means it is //quite easy for this routine to overflow and underflow. Be careful that //your inputs are ok. //#ifndef __powerc #if 0 vms_vector *vm_vec_crossprod(vms_vector *dest,vms_vector *src0,vms_vector *src1) { double d; Assert(dest!=src0 && dest!=src1); d = (double)(src0->y) * (double)(src1->z); d += (double)-(src0->z) * (double)(src1->y); d /= 65536.0; if (d < 0.0) d = d - 1.0; dest->x = (fix)d; d = (double)(src0->z) * (double)(src1->x); d += (double)-(src0->x) * (double)(src1->z); d /= 65536.0; if (d < 0.0) d = d - 1.0; dest->y = (fix)d; d = (double)(src0->x) * (double)(src1->y); d += (double)-(src0->y) * (double)(src1->x); d /= 65536.0; if (d < 0.0) d = d - 1.0; dest->z = (fix)d; return dest; } #else vms_vector *vm_vec_crossprod(vms_vector *dest,vms_vector *src0,vms_vector *src1) { quadint q; Assert(dest!=src0 && dest!=src1); q.low = q.high = 0; fixmulaccum(&q,src0->y,src1->z); fixmulaccum(&q,-src0->z,src1->y); dest->x = fixquadadjust(&q); q.low = q.high = 0; fixmulaccum(&q,src0->z,src1->x); fixmulaccum(&q,-src0->x,src1->z); dest->y = fixquadadjust(&q); q.low = q.high = 0; fixmulaccum(&q,src0->x,src1->y); fixmulaccum(&q,-src0->y,src1->x); dest->z = fixquadadjust(&q); return dest; } #endif //computes non-normalized surface normal from three points. //returns ptr to dest //dest CANNOT equal either source vms_vector *vm_vec_perp(vms_vector *dest,vms_vector *p0,vms_vector *p1,vms_vector *p2) { vms_vector t0,t1; vm_vec_sub(&t0,p1,p0); vm_vec_sub(&t1,p2,p1); check_vec(&t0); check_vec(&t1); return vm_vec_crossprod(dest,&t0,&t1); } //computes the delta angle between two vectors. //vectors need not be normalized. if they are, call vm_vec_delta_ang_norm() //the forward vector (third parameter) can be NULL, in which case the absolute //value of the angle in returned. Otherwise the angle around that vector is //returned. fixang vm_vec_delta_ang(vms_vector *v0,vms_vector *v1,vms_vector *fvec) { vms_vector t0,t1; vm_vec_copy_normalize(&t0,v0); vm_vec_copy_normalize(&t1,v1); return vm_vec_delta_ang_norm(&t0,&t1,fvec); } //computes the delta angle between two normalized vectors. fixang vm_vec_delta_ang_norm(vms_vector *v0,vms_vector *v1,vms_vector *fvec) { fixang a; a = fix_acos(vm_vec_dot(v0,v1)); if (fvec) { vms_vector t; vm_vec_cross(&t,v0,v1); if (vm_vec_dot(&t,fvec) < 0) a = -a; } return a; } vms_matrix *sincos_2_matrix(vms_matrix *m,fix sinp,fix cosp,fix sinb,fix cosb,fix sinh,fix cosh) { fix sbsh,cbch,cbsh,sbch; sbsh = fixmul(sinb,sinh); cbch = fixmul(cosb,cosh); cbsh = fixmul(cosb,sinh); sbch = fixmul(sinb,cosh); m->rvec.x = cbch + fixmul(sinp,sbsh); //m1 m->uvec.z = sbsh + fixmul(sinp,cbch); //m8 m->uvec.x = fixmul(sinp,cbsh) - sbch; //m2 m->rvec.z = fixmul(sinp,sbch) - cbsh; //m7 m->fvec.x = fixmul(sinh,cosp); //m3 m->rvec.y = fixmul(sinb,cosp); //m4 m->uvec.y = fixmul(cosb,cosp); //m5 m->fvec.z = fixmul(cosh,cosp); //m9 m->fvec.y = -sinp; //m6 return m; } //computes a matrix from a set of three angles. returns ptr to matrix vms_matrix *vm_angles_2_matrix(vms_matrix *m,vms_angvec *a) { fix sinp,cosp,sinb,cosb,sinh,cosh; fix_sincos(a->p,&sinp,&cosp); fix_sincos(a->b,&sinb,&cosb); fix_sincos(a->h,&sinh,&cosh); return sincos_2_matrix(m,sinp,cosp,sinb,cosb,sinh,cosh); } //computes a matrix from a forward vector and an angle vms_matrix *vm_vec_ang_2_matrix(vms_matrix *m,vms_vector *v,fixang a) { fix sinb,cosb,sinp,cosp,sinh,cosh; fix_sincos(a,&sinb,&cosb); sinp = -v->y; cosp = fix_sqrt(f1_0 - fixmul(sinp,sinp)); sinh = fixdiv(v->x,cosp); cosh = fixdiv(v->z,cosp); return sincos_2_matrix(m,sinp,cosp,sinb,cosb,sinh,cosh); } //computes a matrix from one or more vectors. The forward vector is required, //with the other two being optional. If both up & right vectors are passed, //the up vector is used. If only the forward vector is passed, a bank of //zero is assumed //returns ptr to matrix vms_matrix *vm_vector_2_matrix(vms_matrix *m,vms_vector *fvec,vms_vector *uvec,vms_vector *rvec) { vms_vector *xvec=&m->rvec,*yvec=&m->uvec,*zvec=&m->fvec; Assert(fvec != NULL); if (vm_vec_copy_normalize(zvec,fvec) == 0) { Int3(); //forward vec should not be zero-length return m; } if (uvec == NULL) { if (rvec == NULL) { //just forward vec bad_vector2: ; if (zvec->x==0 && zvec->z==0) { //forward vec is straight up or down m->rvec.x = f1_0; m->uvec.z = (zvec->y<0)?f1_0:-f1_0; m->rvec.y = m->rvec.z = m->uvec.x = m->uvec.y = 0; } else { //not straight up or down xvec->x = zvec->z; xvec->y = 0; xvec->z = -zvec->x; vm_vec_normalize(xvec); vm_vec_crossprod(yvec,zvec,xvec); } } else { //use right vec if (vm_vec_copy_normalize(xvec,rvec) == 0) goto bad_vector2; vm_vec_crossprod(yvec,zvec,xvec); //normalize new perpendicular vector if (vm_vec_normalize(yvec) == 0) goto bad_vector2; //now recompute right vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(xvec,yvec,zvec); } } else { //use up vec if (vm_vec_copy_normalize(yvec,uvec) == 0) goto bad_vector2; vm_vec_crossprod(xvec,yvec,zvec); //normalize new perpendicular vector if (vm_vec_normalize(xvec) == 0) goto bad_vector2; //now recompute up vector, in case it wasn't entirely perpendiclar vm_vec_crossprod(yvec,zvec,xvec); } return m; } //rotates a vector through a matrix. returns ptr to dest vector //dest CANNOT equal source vms_vector *vm_vec_rotate(vms_vector *dest,const vms_vector *src,const vms_matrix *m) { Assert(dest != src); dest->x = vm_vec_dot(src,&m->rvec); dest->y = vm_vec_dot(src,&m->uvec); dest->z = vm_vec_dot(src,&m->fvec); return dest; } //transpose a matrix in place. returns ptr to matrix vms_matrix *vm_transpose_matrix(vms_matrix *m) { fix t; t = m->uvec.x; m->uvec.x = m->rvec.y; m->rvec.y = t; t = m->fvec.x; m->fvec.x = m->rvec.z; m->rvec.z = t; t = m->fvec.y; m->fvec.y = m->uvec.z; m->uvec.z = t; return m; } //copy and transpose a matrix. returns ptr to matrix //dest CANNOT equal source. use vm_transpose_matrix() if this is the case vms_matrix *vm_copy_transpose_matrix(vms_matrix *dest,vms_matrix *src) { Assert(dest != src); dest->rvec.x = src->rvec.x; dest->rvec.y = src->uvec.x; dest->rvec.z = src->fvec.x; dest->uvec.x = src->rvec.y; dest->uvec.y = src->uvec.y; dest->uvec.z = src->fvec.y; dest->fvec.x = src->rvec.z; dest->fvec.y = src->uvec.z; dest->fvec.z = src->fvec.z; return dest; } //mulitply 2 matrices, fill in dest. returns ptr to dest //dest CANNOT equal either source vms_matrix *vm_matrix_x_matrix(vms_matrix *dest,vms_matrix *src0,vms_matrix *src1) { Assert(dest!=src0 && dest!=src1); dest->rvec.x = vm_vec_dot3(src0->rvec.x,src0->uvec.x,src0->fvec.x, &src1->rvec); dest->uvec.x = vm_vec_dot3(src0->rvec.x,src0->uvec.x,src0->fvec.x, &src1->uvec); dest->fvec.x = vm_vec_dot3(src0->rvec.x,src0->uvec.x,src0->fvec.x, &src1->fvec); dest->rvec.y = vm_vec_dot3(src0->rvec.y,src0->uvec.y,src0->fvec.y, &src1->rvec); dest->uvec.y = vm_vec_dot3(src0->rvec.y,src0->uvec.y,src0->fvec.y, &src1->uvec); dest->fvec.y = vm_vec_dot3(src0->rvec.y,src0->uvec.y,src0->fvec.y, &src1->fvec); dest->rvec.z = vm_vec_dot3(src0->rvec.z,src0->uvec.z,src0->fvec.z, &src1->rvec); dest->uvec.z = vm_vec_dot3(src0->rvec.z,src0->uvec.z,src0->fvec.z, &src1->uvec); dest->fvec.z = vm_vec_dot3(src0->rvec.z,src0->uvec.z,src0->fvec.z, &src1->fvec); return dest; } //extract angles from a matrix vms_angvec *vm_extract_angles_matrix(vms_angvec *a,vms_matrix *m) { fix sinh,cosh,cosp; if (m->fvec.x==0 && m->fvec.z==0) //zero head a->h = 0; else a->h = fix_atan2(m->fvec.z,m->fvec.x); fix_sincos(a->h,&sinh,&cosh); if (abs(sinh) > abs(cosh)) //sine is larger, so use it cosp = fixdiv(m->fvec.x,sinh); else //cosine is larger, so use it cosp = fixdiv(m->fvec.z,cosh); if (cosp==0 && m->fvec.y==0) a->p = 0; else a->p = fix_atan2(cosp,-m->fvec.y); if (cosp == 0) //the cosine of pitch is zero. we're pitched straight up. say no bank a->b = 0; else { fix sinb,cosb; sinb = fixdiv(m->rvec.y,cosp); cosb = fixdiv(m->uvec.y,cosp); if (sinb==0 && cosb==0) a->b = 0; else a->b = fix_atan2(cosb,sinb); } return a; } //extract heading and pitch from a vector, assuming bank==0 vms_angvec *vm_extract_angles_vector_normalized(vms_angvec *a,vms_vector *v) { a->b = 0; //always zero bank a->p = fix_asin(-v->y); if (v->x==0 && v->z==0) a->h = 0; else a->h = fix_atan2(v->z,v->x); return a; } //extract heading and pitch from a vector, assuming bank==0 vms_angvec *vm_extract_angles_vector(vms_angvec *a,vms_vector *v) { vms_vector t; if (vm_vec_copy_normalize(&t,v) != 0) vm_extract_angles_vector_normalized(a,&t); return a; } //compute the distance from a point to a plane. takes the normalized normal //of the plane (ebx), a point on the plane (edi), and the point to check (esi). //returns distance in eax //distance is signed, so negative dist is on the back of the plane fix vm_dist_to_plane(const vms_vector *checkp,const vms_vector *norm,const vms_vector *planep) { vms_vector t; vm_vec_sub(&t,checkp,planep); return vm_vec_dot(&t,norm); } vms_vector *vm_vec_make(vms_vector *v,fix x,fix y,fix z) { v->x=x; v->y=y; v->z=z; return v; } // convert vms_matrix to vms_quaternion void vms_quaternion_from_matrix(vms_quaternion * q, const vms_matrix * m) { fix tr = m->rvec.x + m->uvec.y + m->fvec.z; if (tr > 0) { fix s = fixmul(fix_sqrt(tr + fl2f(1.0)), fl2f(2.0)); q->w = fixmul(fl2f(0.25), s) * .5; q->x = fixdiv(m->fvec.y - m->uvec.z, s) * .5; q->y = fixdiv(m->rvec.z - m->fvec.x, s) * .5; q->z = fixdiv(m->uvec.x - m->rvec.y, s) * .5; } else if ((m->rvec.x > m->uvec.y)&(m->rvec.x > m->fvec.z)) { fix s = fixmul(fix_sqrt(fl2f(1.0) + m->rvec.x - m->uvec.y - m->fvec.z), fl2f(2.0)); q->w = fixdiv(m->fvec.y - m->uvec.z, s) * .5; q->x = fixmul(fl2f(0.25), s) * .5; q->y = fixdiv(m->rvec.y + m->uvec.x, s) * .5; q->z = fixdiv(m->rvec.z + m->fvec.x, s) * .5; } else if (m->uvec.y > m->fvec.z) { fix s = fixmul(fix_sqrt(fl2f(1.0) + m->uvec.y - m->rvec.x - m->fvec.z), fl2f(2.0)); q->w = fixdiv(m->rvec.z - m->fvec.x, s) * .5; q->x = fixdiv(m->rvec.y + m->uvec.x ,s) * .5; q->y = fixmul(fl2f(0.25), s) * .5; q->z = fixdiv(m->uvec.z + m->fvec.y , s) * .5; } else { fix s = fixmul(fix_sqrt(fl2f(1.0) + m->fvec.z - m->rvec.x - m->uvec.y), fl2f(2.0)); q->w = fixdiv(m->uvec.x - m->rvec.y , s) * .5; q->x = fixdiv(m->rvec.z + m->fvec.x , s) * .5; q->y = fixdiv(m->uvec.z + m->fvec.y, s) * .5; q->z = fixmul(fl2f(0.25), s) * .5; } } // convert vms_quaternion to vms_matrix void vms_matrix_from_quaternion(vms_matrix * m, const vms_quaternion * q) { fix sqw = fixmul(q->w * 2, q->w * 2); fix sqx = fixmul(q->x * 2, q->x * 2); fix sqy = fixmul(q->y * 2, q->y * 2); fix sqz = fixmul(q->z * 2, q->z * 2); fix invs = fixdiv(fl2f(1.0), (sqw + sqx + sqy + sqz)); fix tmp1, tmp2; m->rvec.x = fixmul(sqx - sqy - sqz + sqw, invs); m->uvec.y = fixmul(-sqx + sqy - sqz + sqw, invs); m->fvec.z = fixmul(-sqx - sqy + sqz + sqw, invs); tmp1 = fixmul(q->x * 2, q->y * 2); tmp2 = fixmul(q->z * 2, q->w * 2); m->uvec.x = fixmul(fixmul(fl2f(2.0), (tmp1 + tmp2)), invs); m->rvec.y = fixmul(fixmul(fl2f(2.0), (tmp1 - tmp2)), invs); tmp1 = fixmul(q->x * 2, q->z * 2); tmp2 = fixmul(q->y * 2, q->w * 2); m->fvec.x = fixmul(fixmul(fl2f(2.0), (tmp1 - tmp2)), invs); m->rvec.z = fixmul(fixmul(fl2f(2.0), (tmp1 + tmp2)), invs); tmp1 = fixmul(q->y * 2, q->z * 2); tmp2 = fixmul(q->x * 2, q->w * 2); m->fvec.y = fixmul(fixmul(fl2f(2.0), (tmp1 + tmp2)), invs); m->uvec.z = fixmul(fixmul(fl2f(2.0), (tmp1 - tmp2)), invs); } dxx-rebirth-0.58.1-d1x/mem/000077500000000000000000000000001217717257200153305ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/mem/mem.c000066400000000000000000000245321217717257200162600ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Files for debugging memory allocator * * */ #include #include #include #include "physfsx.h" #include "pstypes.h" #include "dxxerror.h" #include "args.h" #include "console.h" #define MEMSTATS 0 #define FULL_MEM_CHECKING 1 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG) #define CHECKSIZE 16 #define CHECKBYTE 0xFC #define MAX_INDEX 10000 static void *MallocBase[MAX_INDEX]; static unsigned int MallocSize[MAX_INDEX]; static unsigned char Present[MAX_INDEX]; static char * Filename[MAX_INDEX]; static char * Varname[MAX_INDEX]; static int LineNum[MAX_INDEX]; static int BytesMalloced = 0; static int free_list[MAX_INDEX]; static int num_blocks = 0; static int Initialized = 0; static int LargestIndex = 0; int out_of_memory = 0; void mem_display_blocks(); void mem_init() { int i; Initialized = 1; for (i=0; i= MAX_INDEX ) { con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" ); con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.\n", var, filename, line ); Error( "MEM_OUT_OF_SLOTS" ); } id = free_list[ num_blocks++ ]; if (id > LargestIndex ) LargestIndex = id; if (id==-1) { con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" ); //con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] ); Error( "MEM_OUT_OF_SLOTS" ); } ptr = malloc( size+CHECKSIZE ); if (ptr==NULL) { out_of_memory = 1; con_printf(CON_CRITICAL, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" ); con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] ); Error( "MEM_OUT_OF_MEMORY" ); } MallocBase[id] = ptr; MallocSize[id] = size; Varname[id] = var; Filename[id] = filename; LineNum[id] = line; Present[id] = 1; pc = (char *)ptr; BytesMalloced += size; for (i=0; i LargestAddress ) LargestAddress = base+size; psize = (int *)ptr; psize--; BytesMalloced += *psize; if (fill_zero) memset( ptr, 0, size ); return ptr; } void mem_free( void * buffer ) { int * psize = (int *)buffer; psize--; if (Initialized==0) mem_init(); #if MEMSTATS { unsigned long theFreeMem = 0; if (sMemStatsFileInitialized) { theFreeMem = FreeMem(); fprintf(sMemStatsFile, "\n%9u bytes free before attempting: FREE", theFreeMem); } } #endif // end of ifdef memstats if (buffer==NULL) { con_printf(CON_CRITICAL, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" ); Warning( "MEM: Freeing the NULL pointer!" ); Int3(); return; } BytesMalloced -= *psize; free( buffer ); } void mem_display_blocks() { if (Initialized==0) return; #if MEMSTATS { if (sMemStatsFileInitialized) { unsigned long theFreeMem = 0; theFreeMem = FreeMem(); fprintf(sMemStatsFile, "\n%9u bytes free before closing MEMSTATS file.", theFreeMem); fprintf(sMemStatsFile, "\nMemory Stats File Closed."); fclose(sMemStatsFile); } } #endif // end of ifdef memstats if (BytesMalloced != 0 ) { con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced ); } if (GameArg.DbgShowMemInfo) { con_printf(CON_CRITICAL, "\n\nMEMORY USAGE:\n" ); con_printf(CON_CRITICAL, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 ); con_printf(CON_CRITICAL, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 ); con_printf(CON_CRITICAL, " ---------------------------\n" ); con_printf(CON_CRITICAL, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 ); } } void mem_validate_heap() { } void mem_print_all() { } #endif dxx-rebirth-0.58.1-d1x/misc/000077500000000000000000000000001217717257200155055ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/misc/args.c000066400000000000000000000145051217717257200166120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions for accessing arguments. * */ #include #include #include #include #include "u_mem.h" #include "physfsx.h" #include "strio.h" #include "strutil.h" #include "args.h" #include "game.h" #include "gauges.h" #ifdef USE_UDP #include "net_udp.h" #endif #define MAX_ARGS 1000 #define INI_FILENAME "d1x.ini" int Num_args=0; char * Args[MAX_ARGS]; struct Arg GameArg; void ReadCmdArgs(void); static int FindArg(const char *const s) { int i; for (i=0; i 0 && endptr && endptr[0] == 'x') { h = strtol(endptr + 1, &endptr, 10); if (h > 0 && endptr[0] == '\0') { *sw = w; *sh = h; return i; } } } return 0; } void AppendIniArgs(void) { PHYSFS_file *f; char *line, *token; char separator[] = " "; f = PHYSFSX_openReadBuffered(INI_FILENAME); if(f) { while(!PHYSFS_eof(f) && Num_args < MAX_ARGS) { line=fgets_unlimited(f); token = strtok(line, separator); /* first token in current line */ if (token) Args[Num_args++] = d_strdup(token); while( token != NULL ) { token = strtok(NULL, separator); /* next tokens in current line */ if (token) Args[Num_args++] = d_strdup(token); } d_free(line); } PHYSFS_close(f); } } // Utility function to get an integer provided as argument int get_int_arg(char *arg_name, int default_value) { int t; return ((t = FindArg(arg_name)) ? atoi(Args[t+1]) : default_value); } // Utility function to get a string provided as argument char *get_str_arg(char *arg_name, char *default_value) { int t; return ((t = FindArg(arg_name)) ? Args[t+1] : default_value); } // All FindArg calls should be here to keep the code clean void ReadCmdArgs(void) { // System Options GameArg.SysShowCmdHelp = (FindArg( "-help" ) || FindArg( "-h" ) || FindArg( "-?" ) || FindArg( "?" )); GameArg.SysUseNiceFPS = !FindArg("-nonicefps"); GameArg.SysMaxFPS = get_int_arg("-maxfps", MAXIMUM_FPS); if (GameArg.SysMaxFPS <= 0 || GameArg.SysMaxFPS > MAXIMUM_FPS) GameArg.SysMaxFPS = MAXIMUM_FPS; GameArg.SysHogDir = get_str_arg("-hogdir", NULL); if (GameArg.SysHogDir == NULL) GameArg.SysNoHogDir = FindArg("-nohogdir"); GameArg.SysUsePlayersDir = FindArg("-use_players_dir"); GameArg.SysLowMem = FindArg("-lowmem"); GameArg.SysPilot = get_str_arg("-pilot", NULL); GameArg.SysWindow = FindArg("-window"); GameArg.SysNoBorders = FindArg("-noborders"); GameArg.SysNoTitles = FindArg("-notitles"); GameArg.SysAutoDemo = FindArg("-autodemo"); // Control Options GameArg.CtlNoCursor = FindArg("-nocursor"); GameArg.CtlNoMouse = FindArg("-nomouse"); GameArg.CtlNoJoystick = FindArg("-nojoystick"); GameArg.CtlNoStickyKeys = FindArg("-nostickykeys"); if (GameArg.CtlNoStickyKeys) // Must happen before SDL_Init! SDL_putenv("SDL_DISABLE_LOCK_KEYS=1"); else SDL_putenv("SDL_DISABLE_LOCK_KEYS=0"); // Sound Options GameArg.SndNoSound = FindArg("-nosound"); GameArg.SndNoMusic = FindArg("-nomusic"); #ifdef USE_SDLMIXER GameArg.SndDisableSdlMixer = FindArg("-nosdlmixer"); #else GameArg.SndDisableSdlMixer = 1; #endif // Graphics Options GameArg.GfxHiresFNTAvailable = !FindArg("-lowresfont"); #ifdef OGL // OpenGL Options GameArg.OglFixedFont = FindArg("-gl_fixedfont"); #endif // Multiplayer Options #ifdef USE_UDP GameArg.MplUdpHostAddr = get_str_arg("-udp_hostaddr", UDP_MANUAL_ADDR_DEFAULT); GameArg.MplUdpHostPort = get_int_arg("-udp_hostport", 0); GameArg.MplUdpMyPort = get_int_arg("-udp_myport", 0); #ifdef USE_TRACKER GameArg.MplTrackerAddr = get_str_arg("-tracker_hostaddr", TRACKER_ADDR_DEFAULT); GameArg.MplTrackerPort = get_int_arg("-tracker_hostport", TRACKER_PORT_DEFAULT); #endif #endif // Editor Options GameArg.EdiNoBm = FindArg("-nobm"); // Debug Options if (FindArg("-debug")) GameArg.DbgVerbose = CON_DEBUG; else if (FindArg("-verbose")) GameArg.DbgVerbose = CON_VERBOSE; else GameArg.DbgVerbose = CON_NORMAL; GameArg.DbgSafelog = FindArg("-safelog"); GameArg.DbgNoRun = FindArg("-norun"); GameArg.DbgRenderStats = FindArg("-renderstats"); GameArg.DbgAltTex = get_str_arg("-text", NULL); GameArg.DbgTexMap = get_str_arg("-tmap", NULL); GameArg.DbgShowMemInfo = FindArg("-showmeminfo"); GameArg.DbgUseDoubleBuffer = !FindArg("-nodoublebuffer"); GameArg.DbgBigPig = !FindArg("-bigpig"); GameArg.DbgBpp = (FindArg("-16bpp") ? 16 : 32); #ifdef OGL GameArg.DbgAltTexMerge = !FindArg("-gl_oldtexmerge"); GameArg.DbgGlIntensity4Ok = get_int_arg("-gl_intensity4_ok", 1); GameArg.DbgGlLuminance4Alpha4Ok = get_int_arg("-gl_luminance4_alpha4_ok", 1); GameArg.DbgGlRGBA2Ok = get_int_arg("-gl_rgba2_ok", 1); GameArg.DbgGlReadPixelsOk = get_int_arg("-gl_readpixels_ok", 1); GameArg.DbgGlGetTexLevelParamOk = get_int_arg("-gl_gettexlevelparam_ok", 1); #else GameArg.DbgSdlHWSurface = FindArg("-hwsurface"); GameArg.DbgSdlASyncBlit = FindArg("-asyncblit"); #endif } void args_exit(void) { int i; for (i=0; i< Num_args; i++ ) d_free(Args[i]); } void InitArgs( int argc,char **argv ) { int i; Num_args=0; for (i=0; i, 2007 */ #include #include "u_mem.h" #include "dl_list.h" dl_list *dl_init() { dl_list *list = d_malloc(sizeof(dl_list)); list->first = NULL; list->last = NULL; list->current = NULL; list->size = 0; return list; } void dl_add(dl_list *list, void *data) { dl_item *item; item = d_malloc(sizeof(dl_item)); item->data = data; item->prev = list->last; item->next = NULL; if (list->last != NULL) { list->last->next = item; } if (list->first == NULL) { list->first = item; list->current = item; } list->last = item; list->size++; } void dl_remove(dl_list *list, dl_item *item) { if (list->current == item) list->current = item->prev; if (list->first == item) list->first = item->next; else item->prev->next = item->next; if (list->last == item) list->last = item->prev; else item->next->prev = item->prev; d_free(item); list->size--; } int dl_is_empty(dl_list const *list) { return (list->first == NULL); } int dl_size(dl_list const *list) { return list->size; } int dl_forward(dl_list *list) { if (!dl_is_empty(list) && list->current->next != NULL) { list->current = list->current->next; return 1; } else return 0; } int dl_backward(dl_list *list) { if (!dl_is_empty(list) && list->current->prev != NULL) { list->current = list->current->prev; return 1; } else return 0; } dxx-rebirth-0.58.1-d1x/misc/error.c000066400000000000000000000046471217717257200170150ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Error handling/printing/exiting code * */ #include #include #include #include #include "pstypes.h" #include "console.h" #include "dxxerror.h" #include "inferno.h" #define MAX_MSG_LEN 256 static void (*ErrorPrintFunc)(const char *); char warn_message[MAX_MSG_LEN]; //takes string in register, calls printf with string on stack void warn_printf(char *s) { con_printf(CON_URGENT, "%s\n",s); } void (*warn_func)(char *s)=warn_printf; //provides a function to call with warning messages void set_warn_func(void (*f)(char *s)) { warn_func = f; } //uninstall warning function - install default printf void clear_warn_func(void (*f)(char *s)) { warn_func = warn_printf; } void print_exit_message(const char *exit_message) { if (ErrorPrintFunc) { (*ErrorPrintFunc)(exit_message); } con_printf(CON_CRITICAL, "\n%s\n",exit_message); } //terminates with error code 1, printing message void Error(const char *fmt,...) { char exit_message[MAX_MSG_LEN]="Error: "; // don't put the new line in for dialog output va_list arglist; va_start(arglist,fmt); vsprintf(exit_message+strlen(exit_message),fmt,arglist); va_end(arglist); Int3(); print_exit_message(exit_message); exit(1); } //print out warning message to user void Warning(char *fmt,...) { va_list arglist; if (warn_func == NULL) return; strcpy(warn_message,"Warning: "); va_start(arglist,fmt); vsprintf(warn_message+strlen(warn_message),fmt,arglist); va_end(arglist); (*warn_func)(warn_message); } //initialize error handling system, and set default message. returns 0=ok int error_init(void (*func)(const char *)) { ErrorPrintFunc = func; // Set Error Print Functions return 0; } dxx-rebirth-0.58.1-d1x/misc/hash.c000066400000000000000000000050751217717257200166030ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to do hash table lookup. * */ #include #include #include #include "dxxerror.h" #include "hash.h" #include "key.h" #include "u_mem.h" #include "strutil.h" int hashtable_init( hashtable *ht, int size ) { int i; ht->size=0; for (i=1; i<12; i++ ) { if ( (1<= size ) { ht->bitsize = i; ht->size = 1<size; ht->and_mask = ht->size - 1; if (ht->size==0) Error( "Hashtable has size of 0" ); ht->key = (char **)d_malloc( size * sizeof(char *) ); if (ht->key==NULL) Error( "Not enough memory to create a hash table of size %d", size ); for (i=0; ikey[i] = NULL; // Use calloc cause we want zero'd array. ht->value = d_malloc( size*sizeof(int) ); if (ht->value==NULL) { d_free(ht->key); Error( "Not enough memory to create a hash table of size %d\n", size ); } ht->nitems = 0; return 0; } void hashtable_free( hashtable *ht ) { if (ht->key != NULL ) d_free( ht->key ); if (ht->value != NULL ) d_free( ht->value ); ht->size = 0; } int hashtable_getkey( char *key ) { int k = 0, i=0; while( *key ) { k^=((int)(*key++))<size ) { j = (k+(i++)) & ht->and_mask; if ( ht->key[j] == NULL ) return -1; if (!d_stricmp(ht->key[j], key )) return ht->value[j]; } return -1; } void hashtable_insert( hashtable *ht, char *key, int value ) { int i,j,k; d_strlwr( key ); k = hashtable_getkey( key ); i = 0; while(i < ht->size) { j = (k+(i++)) & ht->and_mask; if ( ht->key[j] == NULL ) { ht->nitems++; ht->key[j] = key; ht->value[j] = value; return; } else if (!d_stricmp( key, ht->key[j] )) { return; } } Error( "Out of hash slots\n" ); } dxx-rebirth-0.58.1-d1x/misc/hmp.c000066400000000000000000000453311217717257200164430ustar00rootroot00000000000000/* * This code handles HMP files. It can: * - Open/read/close HMP files * - Play HMP via Windows MIDI * - Convert HMP to MIDI for further use * Based on work of Arne de Bruijn and the JFFEE project */ #include #include #include #include "hmp.h" #include "u_mem.h" #include "console.h" #include "timer.h" #ifdef WORDS_BIGENDIAN #define MIDIINT(x) (x) #define MIDISHORT(x) (x) #else #define MIDIINT(x) SWAPINT(x) #define MIDISHORT(x) SWAPSHORT(x) #endif #ifdef _WIN32 int midi_volume; int channel_volume[16]; void hmp_stop(hmp_file *hmp); #endif // READ/OPEN/CLOSE HMP void hmp_close(hmp_file *hmp) { int i; #ifdef _WIN32 hmp_stop(hmp); #endif for (i = 0; i < hmp->num_trks; i++) if (hmp->trks[i].data) d_free(hmp->trks[i].data); d_free(hmp); } hmp_file *hmp_open(const char *filename) { int i, data, num_tracks, tempo; char buf[256]; PHYSFS_file *fp; hmp_file *hmp; unsigned char *p; if (!(fp = PHYSFSX_openReadBuffered((char *)filename))) return NULL; hmp = d_malloc(sizeof(hmp_file)); if (!hmp) { PHYSFS_close(fp); return NULL; } memset(hmp, 0, sizeof(*hmp)); if ((PHYSFS_read(fp, buf, 1, 8) != 8) || (memcmp(buf, "HMIMIDIP", 8))) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } if (PHYSFSX_fseek(fp, 0x30, SEEK_SET)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } if (PHYSFS_read(fp, &num_tracks, 4, 1) != 1) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } if ((num_tracks < 1) || (num_tracks > HMP_TRACKS)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } hmp->num_trks = num_tracks; if (PHYSFSX_fseek(fp, 0x38, SEEK_SET)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } if (PHYSFS_read(fp, &tempo, 4, 1) != 1) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } hmp->tempo = INTEL_INT(tempo); if (PHYSFSX_fseek(fp, 0x308, SEEK_SET)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } for (i = 0; i < num_tracks; i++) { if ((PHYSFSX_fseek(fp, 4, SEEK_CUR)) || (PHYSFS_read(fp, &data, 4, 1) != 1)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } data -= 12; hmp->trks[i].len = data; if (!(p = hmp->trks[i].data = d_malloc(data))) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } /* finally, read track data */ if ((PHYSFSX_fseek(fp, 4, SEEK_CUR)) || (PHYSFS_read(fp, p, data, 1) != 1)) { PHYSFS_close(fp); hmp_close(hmp); return NULL; } hmp->trks[i].loop_set = 0; } hmp->filesize = PHYSFS_fileLength(fp); PHYSFS_close(fp); return hmp; } #ifdef _WIN32 // PLAY HMP AS MIDI void hmp_stop(hmp_file *hmp) { MIDIHDR *mhdr; if (!hmp->stop) { hmp->stop = 1; //PumpMessages(); midiStreamStop(hmp->hmidi); while (hmp->bufs_in_mm) timer_delay(1); } while ((mhdr = hmp->evbuf)) { midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR)); hmp->evbuf = mhdr->lpNext; d_free(mhdr); } if (hmp->hmidi) { midiStreamClose(hmp->hmidi); hmp->hmidi = NULL; } } /* * read a HMI type variable length number */ static int get_var_num_hmi(unsigned char *data, int datalen, unsigned long *value) { unsigned char *p; unsigned long v = 0; int shift = 0; p = data; while ((datalen > 0) && !(*p & 0x80)) { v += *(p++) << shift; shift += 7; datalen --; } if (!datalen) return 0; v += (*(p++) & 0x7f) << shift; if (value) *value = v; return p - data; } /* * read a MIDI type variable length number */ static int get_var_num(unsigned char *data, int datalen, unsigned long *value) { unsigned char *orgdata = data; unsigned long v = 0; while ((datalen > 0) && (*data & 0x80)) v = (v << 7) + (*(data++) & 0x7f); if (!datalen) return 0; v = (v << 7) + *(data++); if (value) *value = v; return data - orgdata; } static int get_event(hmp_file *hmp, event *ev) { static int cmdlen[7]={3,3,3,3,2,2,3}; unsigned long got; unsigned long mindelta, delta; int i, ev_num; hmp_track *trk, *fndtrk; mindelta = INT_MAX; fndtrk = NULL; for (trk = hmp->trks, i = hmp->num_trks; (i--) > 0; trk++) { if (!trk->left || (hmp->loop_start && hmp->looping && !trk->loop_set)) continue; if (!(got = get_var_num_hmi(trk->cur, trk->left, &delta))) return HMP_INVALID_FILE; if (trk->left > got + 2 && *(trk->cur + got) == 0xff && *(trk->cur + got + 1) == 0x2f) {/* end of track */ trk->left = 0; continue; } if (hmp->loop_start && hmp->looping) if (trk->cur == trk->loop) delta = trk->loop_start - hmp->loop_start; delta += trk->cur_time - hmp->cur_time; if (delta < mindelta) { mindelta = delta; fndtrk = trk; } } if (!(trk = fndtrk)) return HMP_EOF; got = get_var_num_hmi(trk->cur, trk->left, &delta); if (hmp->loop_start && hmp->looping) if (trk->cur == trk->loop) delta = trk->loop_start - hmp->loop_start; trk->cur_time += delta; if (!hmp->loop_start && *(trk->cur + got) >> 4 == MIDI_CONTROL_CHANGE && *(trk->cur + got + 1) == HMP_LOOP_START) { hmp->loop_start = trk->cur_time; if ((hmp->filesize == 86949) && (trk->cur_time == 29)) // special ugly HACK HACK HACK for Descent2-version of descent.hmp where loop at this point causes instruments not being reset properly. No track supporting HMP loop I know of meets the requirements for the condition below and even if so - it only disabled the HMP loop feature. { hmp->loop_start = 0; } } if (!hmp->loop_end && *(trk->cur + got) >> 4 == MIDI_CONTROL_CHANGE && *(trk->cur + got + 1) == HMP_LOOP_END) hmp->loop_end = trk->cur_time; if (hmp->loop_start && !trk->loop_set && trk->cur_time >= hmp->loop_start) { trk->loop_start = trk->cur_time; trk->loop = trk->cur; trk->len = trk->left; trk->loop_set = 1; } if (hmp->loop_end && trk->cur_time > hmp->loop_end) return HMP_EOF; ev->delta = trk->cur_time - hmp->cur_time; hmp->cur_time = trk->cur_time; if ((trk->left -= got) < 3) return HMP_INVALID_FILE; trk->cur += got; /*memset(ev, 0, sizeof(*ev));*/ev->datalen = 0; ev->msg[0] = ev_num = *(trk->cur++); trk->left--; if (ev_num < 0x80) return HMP_INVALID_FILE; /* invalid command */ if (ev_num < 0xf0) { ev->msg[1] = *(trk->cur++); trk->left--; if (cmdlen[((ev_num) >> 4) - 8] == 3) { ev->msg[2] = *(trk->cur++); trk->left--; if (ev->msg[0] >> 4 == MIDI_CONTROL_CHANGE && ev->msg[1] == MIDI_VOLUME) { channel_volume[ev->msg[0] & 0xf] = ev->msg[2]; ev->msg[2] = ev->msg[2] * midi_volume / MIDI_VOLUME_SCALE; } } } else if (ev_num == 0xff) { ev->msg[1] = *(trk->cur++); trk->left--; if (!(got = get_var_num(ev->data = trk->cur, trk->left, (unsigned long *)&ev->datalen))) return HMP_INVALID_FILE; trk->cur += ev->datalen; if (trk->left <= ev->datalen) return HMP_INVALID_FILE; trk->left -= ev->datalen; } else /* sysex -> error */ return HMP_INVALID_FILE; return 0; } static int fill_buffer(hmp_file *hmp) { MIDIHDR *mhdr = hmp->evbuf; unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded); unsigned int *pend = (unsigned int *)(mhdr->lpData + mhdr->dwBufferLength); unsigned int i; event ev; memset(&ev, 0, sizeof(event)); while (p + 4 <= pend) { if (hmp->pending_size) { i = (p - pend) * 4; if (i > hmp->pending_size) i = hmp->pending_size; *(p++) = hmp->pending_event | i; *(p++) = 0; memcpy((unsigned char *)p, hmp->pending, i); hmp->pending_size -= i; p += (i + 3) / 4; } else { if ((i = get_event(hmp, &ev))) { mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData); return i; } if (ev.datalen) { hmp->pending_size = ev.datalen; hmp->pending = ev.data; hmp->pending_event = ev.msg[0] << 24; } else { *(p++) = ev.delta; *(p++) = 0; *(p++) = (((DWORD)MEVT_SHORTMSG) << 24) | ((DWORD)ev.msg[0]) | (((DWORD)ev.msg[1]) << 8) | (((DWORD)ev.msg[2]) << 16); } } } mhdr->dwBytesRecorded = ((unsigned char *)p) - ((unsigned char *)mhdr->lpData); return 0; } static int setup_buffers(hmp_file *hmp) { int i; MIDIHDR *buf, *lastbuf; lastbuf = NULL; for (i = 0; i < HMP_BUFFERS; i++) { if (!(buf = d_malloc(HMP_BUFSIZE + sizeof(MIDIHDR)))) return HMP_OUT_OF_MEM; memset(buf, 0, sizeof(MIDIHDR)); buf->lpData = (char *)buf + sizeof(MIDIHDR); buf->dwBufferLength = HMP_BUFSIZE; buf->dwUser = (DWORD)hmp; buf->lpNext = lastbuf; lastbuf = buf; } hmp->evbuf = lastbuf; return 0; } static void reset_tracks(struct hmp_file *hmp) { int i; for (i = 0; i < hmp->num_trks; i++) { if (hmp->trks[i].loop_set) hmp->trks[i].cur = hmp->trks[i].loop; else hmp->trks[i].cur = hmp->trks[i].data; hmp->trks[i].left = hmp->trks[i].len; hmp->trks[i].cur_time = 0; } hmp->cur_time = 0; } static void _stdcall midi_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { MIDIHDR *mhdr; hmp_file *hmp; int rc; if (uMsg != MOM_DONE) return; mhdr = ((MIDIHDR *)dw1); mhdr->dwBytesRecorded = 0; hmp = (hmp_file *)(mhdr->dwUser); mhdr->lpNext = hmp->evbuf; hmp->evbuf = mhdr; hmp->bufs_in_mm--; if (!hmp->stop) { while (fill_buffer(hmp) == HMP_EOF) { if (hmp->bLoop) hmp->stop = 0; else hmp->stop = 1; hmp->looping = 1; reset_tracks(hmp); } if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf, sizeof(MIDIHDR))) != MMSYSERR_NOERROR) { /* ??? */ } else { hmp->evbuf = hmp->evbuf->lpNext; hmp->bufs_in_mm++; } } } static void setup_tempo(hmp_file *hmp, unsigned long tempo) { MIDIHDR *mhdr = hmp->evbuf; unsigned int *p = (unsigned int *)(mhdr->lpData + mhdr->dwBytesRecorded); *(p++) = 0; *(p++) = 0; *(p++) = (((DWORD)MEVT_TEMPO)<<24) | tempo; mhdr->dwBytesRecorded += 12; } void hmp_setvolume(hmp_file *hmp, int volume) { int channel; if (hmp) for (channel = 0; channel < 16; channel++) midiOutShortMsg((HMIDIOUT)hmp->hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_VOLUME << 8 | (channel_volume[channel] * volume / MIDI_VOLUME_SCALE) << 16)); midi_volume = volume; } int hmp_play(hmp_file *hmp, int bLoop) { int rc; MIDIPROPTIMEDIV mptd; hmp->bLoop = bLoop; hmp->loop_start = 0; hmp->loop_end = 0; hmp->looping = 0; hmp->devid = MIDI_MAPPER; if ((rc = setup_buffers(hmp))) return rc; if ((midiStreamOpen(&hmp->hmidi, &hmp->devid,1, (DWORD) (size_t) midi_callback, 0, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { hmp->hmidi = NULL; return HMP_MM_ERR; } mptd.cbStruct = sizeof(mptd); mptd.dwTimeDiv = hmp->tempo; if ((midiStreamProperty(hmp->hmidi,(LPBYTE)&mptd,MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR) { return HMP_MM_ERR; } reset_tracks(hmp); setup_tempo(hmp, 0x0f4240); hmp->stop = 0; while (hmp->evbuf) { if ((rc = fill_buffer(hmp))) { if (rc == HMP_EOF) { reset_tracks(hmp); continue; } else return rc; } if ((rc = midiOutPrepareHeader((HMIDIOUT)hmp->hmidi, hmp->evbuf, sizeof(MIDIHDR))) != MMSYSERR_NOERROR) { return HMP_MM_ERR; } if ((rc = midiStreamOut(hmp->hmidi, hmp->evbuf, sizeof(MIDIHDR))) != MMSYSERR_NOERROR) { return HMP_MM_ERR; } hmp->evbuf = hmp->evbuf->lpNext; hmp->bufs_in_mm++; } midiStreamRestart(hmp->hmidi); return 0; } void hmp_pause(hmp_file *hmp) { if (hmp) midiStreamPause(hmp->hmidi); } void hmp_resume(hmp_file *hmp) { if (hmp) midiStreamRestart(hmp->hmidi); } void hmp_reset() { HMIDIOUT hmidi; MIDIHDR mhdr; MMRESULT rval; int channel; char GS_Reset[] = { 0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7 }; if ((rval = midiOutOpen(&hmidi, MIDI_MAPPER, 0, 0, 0)) != MMSYSERR_NOERROR) { switch (rval) { case MIDIERR_NODEVICE: con_printf(CON_DEBUG, "midiOutOpen Error: no MIDI port was found.\n"); break; case MMSYSERR_ALLOCATED: con_printf(CON_DEBUG, "midiOutOpen Error: specified resource is already allocated.\n"); break; case MMSYSERR_BADDEVICEID: con_printf(CON_DEBUG, "midiOutOpen Error: specified device identifier is out of range.\n"); break; case MMSYSERR_INVALPARAM: con_printf(CON_DEBUG, "midiOutOpen Error: specified pointer or structure is invalid.\n"); break; case MMSYSERR_NOMEM: con_printf(CON_DEBUG, "midiOutOpen Error: unable to allocate or lock memory.\n"); break; default: con_printf(CON_DEBUG, "midiOutOpen Error code %i\n",rval); break; } return; } for (channel = 0; channel < 16; channel++) { midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_ALL_SOUNDS_OFF << 8 | 0 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_RESET_ALL_CONTROLLERS << 8 | 0 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_ALL_NOTES_OFF << 8 | 0 << 16)); channel_volume[channel] = 100; midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_PANPOT << 8 | 64 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_REVERB << 8 | 40 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_CHORUS << 8 | 0 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_BANK_SELECT_MSB << 8 | 0 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_BANK_SELECT_LSB << 8 | 0 << 16)); midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_PROGRAM_CHANGE << 4 | 0 << 8)); } mhdr.lpData = GS_Reset; mhdr.dwBufferLength = sizeof(GS_Reset); mhdr.dwFlags = 0; if ((rval = midiOutPrepareHeader(hmidi, &mhdr, sizeof(MIDIHDR))) == MMSYSERR_NOERROR) { if ((rval = midiOutLongMsg(hmidi, &mhdr, sizeof(MIDIHDR))) == MMSYSERR_NOERROR) { fix64 wait_done = timer_query(); while (!(mhdr.dwFlags & MHDR_DONE)) { timer_update(); if (timer_query() >= wait_done + F1_0) { con_printf(CON_DEBUG, "hmp_reset: Timeout waiting for MHDR_DONE\n"); break; } } } else { switch (rval) { case MIDIERR_NOTREADY: con_printf(CON_DEBUG, "midiOutLongMsg Error: the hardware is busy with other data.\n"); break; case MIDIERR_UNPREPARED: con_printf(CON_DEBUG, "midiOutLongMsg Error: the buffer pointed to by lpMidiOutHdr has not been prepared.\n"); break; case MMSYSERR_INVALHANDLE: con_printf(CON_DEBUG, "midiOutLongMsg Error: the specified device handle is invalid.\n"); break; case MMSYSERR_INVALPARAM: con_printf(CON_DEBUG, "midiOutLongMsg Error: the specified pointer or structure is invalid.\n"); break; default: con_printf(CON_DEBUG, "midiOutLongMsg Error code %i\n",rval); break; } } midiOutUnprepareHeader(hmidi, &mhdr, sizeof(MIDIHDR)); timer_delay(F1_0/20); } else { switch (rval) { case MMSYSERR_INVALHANDLE: con_printf(CON_DEBUG, "midiOutPrepareHeader Error: The specified device handle is invalid.\n"); break; case MMSYSERR_INVALPARAM: con_printf(CON_DEBUG, "midiOutPrepareHeader Error: The specified address is invalid or the given stream buffer is greater than 64K.\n"); break; case MMSYSERR_NOMEM: con_printf(CON_DEBUG, "midiOutPrepareHeader Error: The system is unable to allocate or lock memory.\n"); break; default: con_printf(CON_DEBUG, "midiOutPrepareHeader Error code %i\n",rval); break; } } for (channel = 0; channel < 16; channel++) midiOutShortMsg(hmidi, (DWORD)(channel | MIDI_CONTROL_CHANGE << 4 | MIDI_VOLUME << 8 | (100 * midi_volume / MIDI_VOLUME_SCALE) << 16)); midiOutClose(hmidi); } #endif // CONVERSION FROM HMP TO MIDI static unsigned int hmptrk2mid(ubyte* data, int size, unsigned char **midbuf, unsigned int *midlen) { ubyte *dptr = data; ubyte lc1 = 0,last_com = 0; uint d; int n1, n2; unsigned int offset = *midlen; while (data < dptr + size) { if (data[0] & 0x80) { ubyte b = (data[0] & 0x7F); *midbuf = d_realloc(*midbuf, *midlen + 1); memcpy(&(*midbuf)[*midlen], &b, 1); *midlen += 1; } else { d = (data[0] & 0x7F); n1 = 0; while ((data[n1] & 0x80) == 0) { n1++; d += (data[n1] & 0x7F) << (n1 * 7); } n1 = 1; while ((data[n1] & 0x80) == 0) { n1++; if (n1 == 4) return 0; } for(n2 = 0; n2 <= n1; n2++) { ubyte b = (data[n1 - n2] & 0x7F); if (n2 != n1) b |= 0x80; *midbuf = d_realloc(*midbuf, *midlen + 1); memcpy(&(*midbuf)[*midlen], &b, 1); *midlen += 1; } data += n1; } data++; if (*data == 0xFF) { //meta? *midbuf = d_realloc(*midbuf, *midlen + 3 + data[2]); memcpy(&(*midbuf)[*midlen], data, 3 + data[2]); *midlen += 3 + data[2]; if (data[1] == 0x2F) break; } else { lc1=data[0] ; if ((lc1&0x80) == 0) return 0; switch (lc1 & 0xF0) { case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0: if (lc1 != last_com) { *midbuf = d_realloc(*midbuf, *midlen + 1); memcpy(&(*midbuf)[*midlen], &lc1, 1); *midlen += 1; } *midbuf = d_realloc(*midbuf, *midlen + 2); memcpy(&(*midbuf)[*midlen], data + 1, 2); *midlen += 2; data += 3; break; case 0xC0: case 0xD0: if (lc1 != last_com) { *midbuf = d_realloc(*midbuf, *midlen + 1); memcpy(&(*midbuf)[*midlen], &lc1, 1); *midlen += 1; } *midbuf = d_realloc(*midbuf, *midlen + 1); memcpy(&(*midbuf)[*midlen], data + 1, 1); *midlen += 1; data += 2; break; default: return 0; } last_com = lc1; } } return (*midlen - offset); } ubyte tempo [19] = {'M','T','r','k',0,0,0,11,0,0xFF,0x51,0x03,0x18,0x80,0x00,0,0xFF,0x2F,0}; void hmp2mid(char *hmp_name, unsigned char **midbuf, unsigned int *midlen) { int mi, i; short ms, time_div = 0xC0; hmp_file *hmp=NULL; hmp = hmp_open(hmp_name); if (hmp == NULL) return; *midlen = 0; time_div = hmp->tempo*1.6; // write MIDI-header *midbuf = d_realloc(*midbuf, *midlen + 4); memcpy(&(*midbuf)[*midlen], "MThd", 4); *midlen += 4; mi = MIDIINT(6); *midbuf = d_realloc(*midbuf, *midlen + sizeof(mi)); memcpy(&(*midbuf)[*midlen], &mi, sizeof(mi)); *midlen += sizeof(mi); ms = MIDISHORT(1); *midbuf = d_realloc(*midbuf, *midlen + sizeof(ms)); memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms)); *midlen += sizeof(ms); ms = MIDISHORT(hmp->num_trks); *midbuf = d_realloc(*midbuf, *midlen + sizeof(ms)); memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms)); *midlen += sizeof(ms); ms = MIDISHORT(time_div); *midbuf = d_realloc(*midbuf, *midlen + sizeof(ms)); memcpy(&(*midbuf)[*midlen], &ms, sizeof(ms)); *midlen += sizeof(ms); *midbuf = d_realloc(*midbuf, *midlen + sizeof(tempo)); memcpy(&(*midbuf)[*midlen], &tempo, sizeof(tempo)); *midlen += sizeof(tempo); // tracks for (i = 1; i < hmp->num_trks; i++) { int midtrklenpos = 0; *midbuf = d_realloc(*midbuf, *midlen + 4); memcpy(&(*midbuf)[*midlen], "MTrk", 4); *midlen += 4; midtrklenpos = *midlen; mi = 0; *midbuf = d_realloc(*midbuf, *midlen + sizeof(mi)); *midlen += sizeof(mi); mi = hmptrk2mid(hmp->trks[i].data, hmp->trks[i].len, midbuf, midlen); mi = MIDIINT(mi); memcpy(&(*midbuf)[midtrklenpos], &mi, 4); } hmp_close(hmp); } dxx-rebirth-0.58.1-d1x/misc/ignorecase.c000066400000000000000000000133251217717257200177740ustar00rootroot00000000000000/** \file ignorecase.c */ #include #include #include #include #include "physfsx.h" #include "ignorecase.h" /** * Please see ignorecase.h for details. * * License: this code is public domain. I make no warranty that it is useful, * correct, harmless, or environmentally safe. * * This particular file may be used however you like, including copying it * verbatim into a closed-source project, exploiting it commercially, and * removing any trace of my name from the source (although I hope you won't * do that). I welcome enhancements and corrections to this file, but I do * not require you to send me patches if you make changes. This code has * NO WARRANTY. * * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. * Please see LICENSE in the root of the source tree. * * \author Ryan C. Gordon. */ /* I'm not screwing around with stricmp vs. strcasecmp... */ static int caseInsensitiveStringCompare(const char *x, const char *y) { int ux, uy; do { ux = toupper((int) *x); uy = toupper((int) *y); if (ux != uy) return((ux > uy) ? 1 : -1); x++; y++; } while ((ux) && (uy)); return(0); } /* caseInsensitiveStringCompare */ static int locateOneElement(char *buf) { char *ptr; char **rc; char **i; if (PHYSFSX_exists(buf,0)) return(1); /* quick rejection: exists in current case. */ ptr = strrchr(buf, '/'); /* find entry at end of path. */ if (ptr == NULL) { rc = PHYSFS_enumerateFiles("/"); ptr = buf; } /* if */ else { *ptr = '\0'; rc = PHYSFS_enumerateFiles(buf); *ptr = '/'; ptr++; /* point past dirsep to entry itself. */ } /* else */ for (i = rc; *i != NULL; i++) { if (caseInsensitiveStringCompare(*i, ptr) == 0) { strcpy(ptr, *i); /* found a match. Overwrite with this case. */ PHYSFS_freeList(rc); return(1); } /* if */ } /* for */ /* no match at all... */ PHYSFS_freeList(rc); return(0); } /* locateOneElement */ int PHYSFSEXT_locateCorrectCase(char *buf) { int rc; char *ptr; char *prevptr; while (*buf == '/') /* skip any '/' at start of string... */ buf++; ptr = prevptr = buf; if (*ptr == '\0') return(0); /* Uh...I guess that's success. */ while ((ptr = strchr(ptr + 1, '/'))) { *ptr = '\0'; /* block this path section off */ rc = locateOneElement(buf); *ptr = '/'; /* restore path separator */ if (!rc) return(-2); /* missing element in path. */ } /* while */ /* check final element... */ return(locateOneElement(buf) ? 0 : -1); } /* PHYSFSEXT_locateCorrectCase */ #ifdef TEST_PHYSFSEXT_LOCATECORRECTCASE int main(int argc, char **argv) { int rc; char buf[128]; PHYSFS_file *f; if (!PHYSFS_init(argv[0])) { con_printf(CON_CRITICAL, "PHYSFS_init(): %s\n", PHYSFS_getLastError()); return(1); } /* if */ if (!PHYSFS_addToSearchPath(".", 1)) { con_printf(CON_CRITICAL, "PHYSFS_addToSearchPath(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ if (!PHYSFS_setWriteDir(".")) { con_printf(CON_CRITICAL, "PHYSFS_setWriteDir(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ if (!PHYSFS_mkdir("/a/b/c")) { con_printf(CON_CRITICAL, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ if (!PHYSFS_mkdir("/a/b/C")) { con_printf(CON_CRITICAL, "PHYSFS_mkdir(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ f = PHYSFS_openWrite("/a/b/c/x.txt"); PHYSFS_close(f); if (f == NULL) { con_printf(CON_CRITICAL, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ f = PHYSFS_openWrite("/a/b/C/X.txt"); PHYSFS_close(f); if (f == NULL) { con_printf(CON_CRITICAL, "PHYSFS_openWrite(): %s\n", PHYSFS_getLastError()); PHYSFS_deinit(); return(1); } /* if */ strcpy(buf, "/a/b/c/x.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0)) con_printf(CON_DEBUG,"test 1 failed\n"); strcpy(buf, "/a/B/c/x.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0)) con_printf(CON_DEBUG,"test 2 failed\n"); strcpy(buf, "/a/b/C/x.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != 0) || (strcmp(buf, "/a/b/C/X.txt") != 0)) con_printf(CON_DEBUG,"test 3 failed\n"); strcpy(buf, "/a/b/c/X.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != 0) || (strcmp(buf, "/a/b/c/x.txt") != 0)) con_printf(CON_DEBUG,"test 4 failed\n"); strcpy(buf, "/a/b/c/z.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != -1) || (strcmp(buf, "/a/b/c/z.txt") != 0)) con_printf(CON_DEBUG,"test 5 failed\n"); strcpy(buf, "/A/B/Z/z.txt"); rc = PHYSFSEXT_locateCorrectCase(buf); if ((rc != -2) || (strcmp(buf, "/a/b/Z/z.txt") != 0)) con_printf(CON_DEBUG,"test 6 failed\n"); con_printf(CON_DEBUG,"Testing completed.\n"); con_printf(CON_DEBUG," If no errors were reported, you're good to go.\n"); PHYSFS_delete("/a/b/c/x.txt"); PHYSFS_delete("/a/b/C/X.txt"); PHYSFS_delete("/a/b/c"); PHYSFS_delete("/a/b/C"); PHYSFS_delete("/a/b"); PHYSFS_delete("/a"); PHYSFS_deinit(); return(0); } /* main */ #endif /* end of ignorecase.c ... */ dxx-rebirth-0.58.1-d1x/misc/physfsx.c000066400000000000000000000335051217717257200173630ustar00rootroot00000000000000/* * * Some simple physfs extensions * */ #if !defined(macintosh) && !defined(_MSC_VER) #include #endif #if defined(__MACH__) && defined(__APPLE__) #include #include // for chdir hack #include #endif #include "physfsx.h" #include "args.h" #include "object.h" #include "newdemo.h" // Initialise PhysicsFS, set up basic search paths and add arguments from .ini file. // The .ini file can be in either the user directory or the same directory as the program. // The user directory is searched first. void PHYSFSX_init(int argc, char *argv[]) { #if defined(__unix__) || defined(__APPLE__) || defined(__MACH__) char fullPath[PATH_MAX + 5]; #endif #if defined(__unix__) char *path = NULL; #endif #ifdef macintosh // Mac OS 9 char base_dir[PATH_MAX]; int bundle = 0; #else #define base_dir PHYSFS_getBaseDir() #endif PHYSFS_init(argv[0]); PHYSFS_permitSymbolicLinks(1); #ifdef macintosh strcpy(base_dir, PHYSFS_getBaseDir()); if (strstr(base_dir, ".app:Contents:MacOSClassic")) // the Mac OS 9 program is still in the .app bundle { char *p; bundle = 1; if (base_dir[strlen(base_dir) - 1] == ':') base_dir[strlen(base_dir) - 1] = '\0'; p = strrchr(base_dir, ':'); *p = '\0'; // path to 'Contents' p = strrchr(base_dir, ':'); *p = '\0'; // path to bundle p = strrchr(base_dir, ':'); *p = '\0'; // path to directory containing bundle } #endif #if (defined(__APPLE__) && defined(__MACH__)) // others? chdir(base_dir); // make sure relative hogdir paths work #endif #if defined(__unix__) # if !(defined(__APPLE__) && defined(__MACH__)) path = "~/.d1x-rebirth/"; # else path = "~/Library/Preferences/D1X Rebirth/"; # endif if (path[0] == '~') // yes, this tilde can be put before non-unix paths. { const char *home = PHYSFS_getUserDir(); strcpy(fullPath, home); // prepend home to the path path++; if (*path == *PHYSFS_getDirSeparator()) path++; strncat(fullPath, path, PATH_MAX + 5 - strlen(home)); } else strncpy(fullPath, path, PATH_MAX + 5); PHYSFS_setWriteDir(fullPath); if (!PHYSFS_getWriteDir()) { // need to make it char *p; char ancestor[PATH_MAX + 5]; // the directory which actually exists char child[PATH_MAX + 5]; // the directory relative to the above we're trying to make strcpy(ancestor, fullPath); while (!PHYSFS_getWriteDir() && ((p = strrchr(ancestor, *PHYSFS_getDirSeparator())))) { if (p[1] == 0) { // separator at the end (intended here, for safety) *p = 0; // kill this separator if (!((p = strrchr(ancestor, *PHYSFS_getDirSeparator())))) break; // give up, this is (usually) the root directory } p[1] = 0; // go to parent PHYSFS_setWriteDir(ancestor); } strcpy(child, fullPath + strlen(ancestor)); for (p = child; (p = strchr(p, *PHYSFS_getDirSeparator())); p++) *p = '/'; PHYSFS_mkdir(child); PHYSFS_setWriteDir(fullPath); } PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 1); #endif PHYSFS_addToSearchPath(base_dir, 1); InitArgs( argc,argv ); PHYSFS_removeFromSearchPath(base_dir); if (!PHYSFS_getWriteDir()) { PHYSFS_setWriteDir(base_dir); if (!PHYSFS_getWriteDir()) Error("can't set write dir: %s\n", PHYSFS_getLastError()); else PHYSFS_addToSearchPath(PHYSFS_getWriteDir(), 0); } //tell PHYSFS where hogdir is if (GameArg.SysHogDir) PHYSFS_addToSearchPath(GameArg.SysHogDir,1); #if defined(__unix__) else if (!GameArg.SysNoHogDir) PHYSFS_addToSearchPath(SHAREPATH, 1); #endif PHYSFSX_addRelToSearchPath("data", 1); // 'Data' subdirectory // For Macintosh, add the 'Resources' directory in the .app bundle to the searchpaths #if defined(__APPLE__) && defined(__MACH__) { ProcessSerialNumber psn = { 0, kCurrentProcess }; FSRef fsref; OSStatus err; err = GetProcessBundleLocation(&psn, &fsref); if (err == noErr) err = FSRefMakePath(&fsref, (ubyte *)fullPath, PATH_MAX); if (err == noErr) { strncat(fullPath, "/Contents/Resources/", PATH_MAX + 4 - strlen(fullPath)); fullPath[PATH_MAX + 4] = '\0'; PHYSFS_addToSearchPath(fullPath, 1); } } #elif defined(macintosh) if (bundle) { base_dir[strlen(base_dir)] = ':'; // go back in the bundle base_dir[strlen(base_dir)] = ':'; // go back in 'Contents' strncat(base_dir, ":Resources:", PATH_MAX - 1 - strlen(base_dir)); base_dir[PATH_MAX - 1] = '\0'; PHYSFS_addToSearchPath(base_dir, 1); } #endif } // Add a searchpath, but that searchpath is relative to an existing searchpath // It will add the first one it finds and return 1, if it doesn't find any it returns 0 int PHYSFSX_addRelToSearchPath(const char *relname, int add_to_end) { char relname2[PATH_MAX], pathname[PATH_MAX]; snprintf(relname2, sizeof(relname2), "%s", relname); PHYSFSEXT_locateCorrectCase(relname2); if (!PHYSFSX_getRealPath(relname2, pathname)) return 0; return PHYSFS_addToSearchPath(pathname, add_to_end); } int PHYSFSX_removeRelFromSearchPath(const char *relname) { char relname2[PATH_MAX], pathname[PATH_MAX]; snprintf(relname2, sizeof(relname2), "%s", relname); PHYSFSEXT_locateCorrectCase(relname2); if (!PHYSFSX_getRealPath(relname2, pathname)) return 0; return PHYSFS_removeFromSearchPath(pathname); } int PHYSFSX_fsize(const char *hogname) { PHYSFS_file *fp; char hogname2[PATH_MAX]; int size; snprintf(hogname2, sizeof(hogname2), "%s", hogname); PHYSFSEXT_locateCorrectCase(hogname2); fp = PHYSFS_openRead(hogname2); if (fp == NULL) return -1; size = PHYSFS_fileLength(fp); PHYSFS_close(fp); return size; } void PHYSFSX_listSearchPathContent() { char **i, **list; con_printf(CON_DEBUG, "PHYSFS: Listing contents of Search Path.\n"); list = PHYSFS_getSearchPath(); for (i = list; *i != NULL; i++) con_printf(CON_DEBUG, "PHYSFS: [%s] is in the Search Path.\n", *i); PHYSFS_freeList(list); list = PHYSFS_enumerateFiles(""); for (i = list; *i != NULL; i++) con_printf(CON_DEBUG, "PHYSFS: * We've got [%s].\n", *i); PHYSFS_freeList(list); con_printf(CON_DEBUG, "\n"); } // checks which archives are supported by PhysFS. Return 0 if some essential (HOG) is not supported int PHYSFSX_checkSupportedArchiveTypes() { const PHYSFS_ArchiveInfo **i; int hog_sup = 0; con_printf(CON_DEBUG, "PHYSFS: Checking supported archive types.\n"); for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++) { con_printf(CON_DEBUG, "PHYSFS: Supported archive: [%s], which is [%s].\n", (*i)->extension, (*i)->description); if (!d_stricmp((*i)->extension, "HOG")) hog_sup = 1; } if (!hog_sup) con_printf(CON_CRITICAL, "PHYSFS: HOG not supported. The game will not work without!\n"); return hog_sup; } int PHYSFSX_getRealPath(const char *stdPath, char *realPath) { const char *realDir = PHYSFS_getRealDir(stdPath); const char *sep = PHYSFS_getDirSeparator(); char *p; if (!realDir) { realDir = PHYSFS_getWriteDir(); if (!realDir) return 0; } strncpy(realPath, realDir, PATH_MAX - 1); if (strlen(realPath) >= strlen(sep)) { p = realPath + strlen(realPath) - strlen(sep); if (strcmp(p, sep)) // no sep at end of realPath strncat(realPath, sep, PATH_MAX - 1 - strlen(realPath)); } if (strlen(stdPath) >= 1) if (*stdPath == '/') stdPath++; while (*stdPath) { if (*stdPath == '/') strncat(realPath, sep, PATH_MAX - 1 - strlen(realPath)); else { if (strlen(realPath) < PATH_MAX - 2) { p = realPath + strlen(realPath); p[0] = *stdPath; p[1] = '\0'; } } stdPath++; } return 1; } // checks if path is already added to Searchpath. Returns 0 if yes, 1 if not. int PHYSFSX_isNewPath(const char *path) { int is_new_path = 1; char **i, **list; list = PHYSFS_getSearchPath(); for (i = list; *i != NULL; i++) { if (!strcmp(path, *i)) { is_new_path = 0; } } PHYSFS_freeList(list); return is_new_path; } int PHYSFSX_rename(const char *oldpath, const char *newpath) { char old[PATH_MAX], new[PATH_MAX]; PHYSFSX_getRealPath(oldpath, old); PHYSFSX_getRealPath(newpath, new); return (rename(old, new) == 0); } // Find files at path that have an extension listed in exts // The extension list exts must be NULL-terminated, with each ext beginning with a '.' char **PHYSFSX_findFiles(const char *path, const char *const *exts) { char **list = PHYSFS_enumerateFiles(path); char **i, **j = list; const char *const *k; char *ext; if (list == NULL) return NULL; // out of memory: not so good for (i = list; *i; i++) { ext = strrchr(*i, '.'); if (ext) for (k = exts; *k != NULL && d_stricmp(ext, *k); k++) {} // see if the file is of a type we want if (ext && *k) *j++ = *i; else free(*i); } *j = NULL; list = realloc(list, (j - list + 1)*sizeof(char *)); // save a bit of memory (or a lot?) return list; } // Same function as above but takes a real directory as second argument, only adding files originating from this directory. // This can be used to further seperate files in search path but it must be made sure realpath is properly formatted. char **PHYSFSX_findabsoluteFiles(const char *path, const char *realpath, const char *const *exts) { char **list = PHYSFS_enumerateFiles(path); char **i, **j = list; const char *const *k; char *ext; if (list == NULL) return NULL; // out of memory: not so good for (i = list; *i; i++) { ext = strrchr(*i, '.'); if (ext) for (k = exts; *k != NULL && d_stricmp(ext, *k); k++) {} // see if the file is of a type we want if (ext && *k && (!strcmp(PHYSFS_getRealDir(*i),realpath))) *j++ = *i; else free(*i); } *j = NULL; list = realloc(list, (j - list + 1)*sizeof(char *)); // save a bit of memory (or a lot?) return list; } #if 0 // returns -1 if error // Gets bytes free in current write dir PHYSFS_sint64 PHYSFSX_getFreeDiskSpace() { #if defined(__LINUX__) || (defined(__MACH__) && defined(__APPLE__)) struct statfs sfs; if (!statfs(PHYSFS_getWriteDir(), &sfs)) return (PHYSFS_sint64)(sfs.f_bavail * sfs.f_bsize); return -1; #else return 0x7FFFFFFF; #endif } #endif int PHYSFSX_exists(const char *filename, int ignorecase) { char filename2[PATH_MAX]; if (!ignorecase) return PHYSFS_exists(filename); snprintf(filename2, sizeof(filename2), "%s", filename); PHYSFSEXT_locateCorrectCase(filename2); return PHYSFS_exists(filename2); } //Open a file for reading, set up a buffer PHYSFS_file *PHYSFSX_openReadBuffered(const char *filename) { PHYSFS_file *fp; PHYSFS_uint64 bufSize; char filename2[PATH_MAX]; if (filename[0] == '\x01') { //FIXME: don't look in dir, only in hogfile filename++; } snprintf(filename2, sizeof(filename2), "%s", filename); PHYSFSEXT_locateCorrectCase(filename2); fp = PHYSFS_openRead(filename2); if (!fp) return NULL; bufSize = PHYSFS_fileLength(fp); while (!PHYSFS_setBuffer(fp, bufSize) && bufSize) bufSize /= 2; // even if the error isn't memory full, for a 20MB file it'll only do this 8 times return fp; } //Open a file for writing, set up a buffer PHYSFS_file *PHYSFSX_openWriteBuffered(const char *filename) { PHYSFS_file *fp; PHYSFS_uint64 bufSize = 1024*1024; // hmm, seems like an OK size. fp = PHYSFS_openWrite(filename); if (!fp) return NULL; while (!PHYSFS_setBuffer(fp, bufSize) && bufSize) bufSize /= 2; return fp; } /* * Add archives to the game. * 1) archives from Sharepath/Data to extend/replace builtin game content * 2) archived demos */ void PHYSFSX_addArchiveContent() { char **list = NULL; static const char *const archive_exts[] = { ".dxa", NULL }; char *file[2]; int i = 0, content_updated = 0; con_printf(CON_DEBUG, "PHYSFS: Adding archives to the game.\n"); // find files in Searchpath ... list = PHYSFSX_findFiles("", archive_exts); // if found, add them... for (i = 0; list[i] != NULL; i++) { MALLOC(file[0], char, PATH_MAX); MALLOC(file[1], char, PATH_MAX); snprintf(file[0], sizeof(char)*PATH_MAX, "%s", list[i]); PHYSFSX_getRealPath(file[0],file[1]); if (PHYSFS_addToSearchPath(file[1], 0)) { con_printf(CON_DEBUG, "PHYSFS: Added %s to Search Path\n",file[1]); content_updated = 1; } d_free(file[0]); d_free(file[1]); } PHYSFS_freeList(list); list = NULL; #if PHYSFS_VER_MAJOR >= 2 // find files in DEMO_DIR ... list = PHYSFSX_findFiles(DEMO_DIR, archive_exts); // if found, add them... for (i = 0; list[i] != NULL; i++) { MALLOC(file[0], char, PATH_MAX); MALLOC(file[1], char, PATH_MAX); snprintf(file[0], sizeof(char)*PATH_MAX, "%s%s", DEMO_DIR, list[i]); PHYSFSX_getRealPath(file[0],file[1]); if (PHYSFS_mount(file[1], DEMO_DIR, 0)) { con_printf(CON_DEBUG, "PHYSFS: Added %s to %s\n",file[1], DEMO_DIR); content_updated = 1; } d_free(file[0]); d_free(file[1]); } PHYSFS_freeList(list); list = NULL; #endif if (content_updated) { con_printf(CON_DEBUG, "Game content updated!\n"); PHYSFSX_listSearchPathContent(); } } // Removes content added above when quitting game void PHYSFSX_removeArchiveContent() { char **list = NULL; static const char *const archive_exts[] = { ".dxa", NULL }; char *file[2]; int i = 0; // find files in Searchpath ... list = PHYSFSX_findFiles("", archive_exts); // if found, remove them... for (i = 0; list[i] != NULL; i++) { MALLOC(file[0], char, PATH_MAX); MALLOC(file[1], char, PATH_MAX); snprintf(file[0], sizeof(char)*PATH_MAX, "%s", list[i]); PHYSFSX_getRealPath(file[0],file[1]); PHYSFS_removeFromSearchPath(file[1]); d_free(file[0]); d_free(file[1]); } PHYSFS_freeList(list); list = NULL; // find files in DEMO_DIR ... list = PHYSFSX_findFiles(DEMO_DIR, archive_exts); // if found, remove them... for (i = 0; list[i] != NULL; i++) { MALLOC(file[0], char, PATH_MAX); MALLOC(file[1], char, PATH_MAX); snprintf(file[0], sizeof(char)*PATH_MAX, "%s%s", DEMO_DIR, list[i]); PHYSFSX_getRealPath(file[0],file[1]); PHYSFS_removeFromSearchPath(file[1]); d_free(file[0]); d_free(file[1]); } PHYSFS_freeList(list); list = NULL; } dxx-rebirth-0.58.1-d1x/misc/strio.c000066400000000000000000000020231217717257200170060ustar00rootroot00000000000000/**strio.c: string/file manipulation functions by Victor Rachels **/ #include #include #include "physfsx.h" #include "strio.h" #include "u_mem.h" char *fgets_unlimited(PHYSFS_file *f) { int mem = 256; char *word, *buf, *p; MALLOC(word, char, mem); p = word; while (word && PHYSFSX_fgets(p, mem, f) == word + mem) { int i; // Make a bigger buffer, because it read to the end of the buffer. buf = word; mem *= 2; MALLOC(word, char, mem); for (i = 0; i < mem/2; i++) word[i] = buf[i]; d_free(buf); p = word + mem/2; } return word; } char* splitword(char *s, char splitchar) { int x,l,l2; char *word; for(l=0;s[l]!=0;l++); for(x=0;s[x]!=splitchar&&x #include #include #include #include #include "u_mem.h" #include "dxxerror.h" #include "strutil.h" #include "inferno.h" #ifdef macintosh void snprintf(char *out_string, int size, char * format, ... ) { va_list args; char buf[1024]; va_start(args, format ); vsprintf(buf,format,args); va_end(args); // Hack! Don't know any other [simple] way to do this, but I doubt it would ever exceed 1024 long. Assert(strlen(buf) < 1024); Assert(size < 1024); strncpy(out_string, buf, size); } # if defined(NDEBUG) char *strdup(const char *str) { char *newstr; newstr = malloc(strlen(str) + 1); strcpy(newstr, str); return newstr; } # endif // NDEBUG #endif // macintosh // string compare without regard to case int d_stricmp( const char *s1, const char *s2 ) { int u1; int u2; do { u1 = toupper((int) *s1); u2 = toupper((int) *s2); if (u1 != u2) return (u1 > u2) ? 1 : -1; s1++; s2++; } while (u1 && u2); return 0; } int d_strnicmp( const char *s1, const char *s2, int n ) { int u1; int u2; do { u1 = toupper((int) *s1); u2 = toupper((int) *s2); if (u1 != u2) return (u1 > u2) ? 1 : -1; s1++; s2++; n--; } while (u1 && u2 && n); return 0; } void d_strlwr( char *s1 ) { while( *s1 ) { *s1 = tolower(*s1); s1++; } } void d_strupr( char *s1 ) { while( *s1 ) { *s1 = toupper(*s1); s1++; } } void d_strrev( char *s1 ) { char *h, *t; h = s1; t = s1 + strlen(s1) - 1; while (h < t) { char c; c = *h; *h++ = *t; *t-- = c; } } char *d_strdup(char *str) { char *newstr; newstr = d_malloc(strlen(str) + 1); strcpy(newstr, str); return newstr; } // remove extension from filename void removeext(const char *filename, char *out) { char *p; if ((p = strrchr(filename, '.'))) { strncpy(out, filename, p - filename); out[p - filename] = 0; } else strcpy(out, filename); } //give a filename a new extension, won't append if strlen(dest) > 8 chars. void change_filename_extension( char *dest, const char *src, char *ext ) { char *p; strcpy (dest, src); if (ext[0] == '.') ext++; p = strrchr(dest, '.'); if (!p) { if (strlen(dest) > FILENAME_LEN - 5) return; // a non-opened file is better than a bad memory access p = dest + strlen(dest); *p = '.'; } strcpy(p+1,ext); } void d_splitpath(char *name, char *drive, char *path, char *base, char *ext) { char *s, *p; p = name; s = strchr(p, ':'); if ( s != NULL ) { if (drive) { *s = '\0'; strcpy(drive, p); *s = ':'; } p = s+1; if (!p) return; } else if (drive) *drive = '\0'; s = strrchr(p, '\\'); if ( s != NULL) { if (path) { char c; c = *(s+1); *(s+1) = '\0'; strcpy(path, p); *(s+1) = c; } p = s+1; if (!p) return; } else if (path) *path = '\0'; s = strchr(p, '.'); if ( s != NULL) { if (base) { *s = '\0'; strcpy(base, p); *s = '.'; } p = s+1; if (!p) return; } else if (base) *base = '\0'; if (ext) strcpy(ext, p); } // create a growing 2D array with a single growing buffer for the text // this system is likely to cause less memory fragmentation than having one malloc'd buffer per string int string_array_new(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf) { *max_str = 1024; MALLOC(*list, char *, 1024); if (*list == NULL) return 0; *max_buf = 1024; // bigger? MALLOC(*list_buf, char, 1024); if (*list_buf == NULL) { d_free(*list); return 0; } *num_str = 0; (*list)[0] = *list_buf; return 1; } int string_array_add(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf, const char *str) { char *next_str = *num_str ? (*list)[*num_str - 1] + strlen((*list)[*num_str - 1]) + 1 : *list_buf; // Need to grow an array? if (*num_str >= *max_str) { char **new_list = d_realloc(*list, *max_str*sizeof(char *)*MEM_K); if (new_list == NULL) return 0; *max_str *= MEM_K; *list = new_list; } if (next_str + strlen(str) + 1 - *list_buf >= *max_buf) { int i; char *new_buf; new_buf = d_realloc(*list_buf, *max_buf*sizeof(char)*MEM_K); if (new_buf == NULL) return 0; // Update all the pointers in the pointer list for (i = 0; i < *num_str; i++) (*list)[i] += (new_buf - *list_buf); *max_buf *= MEM_K; *list_buf = new_buf; next_str = *num_str ? (*list)[*num_str - 1] + strlen((*list)[*num_str - 1]) + 1 : *list_buf; } strcpy(next_str, str); (*list)[(*num_str)++] = next_str; return 1; } int string_array_sort_func(char **e0, char **e1) { return d_stricmp(*e0, *e1); } void string_array_tidy(char ***list, char **list_buf, int *num_str, int *max_str, int *max_buf, int offset, int (*comp)( const char *, const char * )) { char *temp_buf, **temp_list; int i, j; // Reduce memory fragmentation temp_list = d_realloc(*list, sizeof(char *)*(*num_str ? *num_str : 1)); if (temp_list) { *list = temp_list; *max_str = *num_str; } j = *num_str ? (*list)[*num_str - 1] + strlen((*list)[*num_str - 1]) + 1 - *list_buf : 1; // buffer size - a bit of variable recycling temp_buf = d_realloc(*list_buf, j); if (temp_buf) { for (i = 0; i < *num_str; i++) (*list)[i] += (temp_buf - *list_buf); *list_buf = temp_buf; *max_buf = j; // set to buffer size used } // Sort by name, starting at offset qsort(&(*list)[offset], *num_str - offset, sizeof(char *), (int (*)( const void *, const void * ))string_array_sort_func); // Remove duplicates // Can't do this before reallocating, otherwise it makes a mess of things (the strings in the buffer aren't ordered) for (i = offset, j = offset; i < *num_str; i++) if ((i == offset) || comp((*list)[i - 1], (*list)[i])) (*list)[j++] = (*list)[i]; *num_str = j; } dxx-rebirth-0.58.1-d1x/texmap/000077500000000000000000000000001217717257200160505ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/texmap/ntmap.c000066400000000000000000000724341217717257200173450ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Start of conversion to new texture mapper. * */ #define VESA 0 #define NUM_TMAPS 16 #define HEADLIGHT_LIGHTING 0 #define WIREFRAME 0 #define PERSPECTIVE 1 #include "pstypes.h" #include "fix.h" #include "vecmat.h" #include "gr.h" #include "3d.h" #include "dxxerror.h" #include "render.h" #include "texmap.h" #include "texmapl.h" #include "rle.h" #include "scanline.h" #ifdef EDITOR #define EDITOR_TMAP 1 //if in, include extra stuff #endif #define F15_5 (F1_0*15 + F0_5) // Temporary texture map, interface from Matt's 3d system to Mike's texture mapper. g3ds_tmap Tmap1; grs_bitmap Texmap_ptrs[NUM_TMAPS]; grs_bitmap Texmap4_ptrs[NUM_TMAPS]; fix Range_max=0; // debug, kill me int Interpolation_method=0; // 0 = choose best method int Lighting_on=1; // initialize to no lighting int Tmap_flat_flag = 0; // 1 = render texture maps as flat shaded polygons. int Current_seg_depth; // HACK INTERFACE: how far away the current segment (& thus texture) is int Max_perspective_depth; int Max_flat_depth; // These variables are the interface to assembler. They get set for each texture map, which is a real waste of time. // They should be set only when they change, which is generally when the window bounds change. And, even still, it's // a pretty bad interface. int bytes_per_row=-1; unsigned char *write_buffer; int window_left; int window_right; int window_top; int window_bottom; int window_width; int window_height; int *y_pointers=NULL; fix fix_recip[FIX_RECIP_TABLE_SIZE]; int Lighting_enabled; int Fix_recip_table_computed=0; fix fx_l, fx_u, fx_v, fx_z, fx_du_dx, fx_dv_dx, fx_dz_dx, fx_dl_dx; int fx_xleft, fx_xright, fx_y; unsigned char * pixptr; int per2_flag = 0; int Transparency_on = 0; int dither_intensity_lighting = 0; ubyte * tmap_flat_cthru_table; ubyte tmap_flat_color; ubyte tmap_flat_shade_value; // ------------------------------------------------------------------------------------- void init_fix_recip_table(void) { int i; fix_recip[0] = F1_0; for (i=1; icv_bitmap; Assert(bp!=NULL); Assert(bp->bm_data!=NULL); if (y_pointers != NULL) { d_free(y_pointers); y_pointers = NULL; } MALLOC(y_pointers, int, bp->bm_h); // If bytes_per_row has changed, create new table of pointers. if (bytes_per_row != (int) bp->bm_rowsize) { int y_val, i; bytes_per_row = (int) bp->bm_rowsize; y_val = 0; for (i=0; ibm_h; i++) { y_pointers[i] = y_val; y_val += bytes_per_row; } } write_buffer = (unsigned char *) bp->bm_data; window_left = 0; window_right = (int) bp->bm_w-1; window_top = 0; window_bottom = (int) bp->bm_h-1; Window_clip_left = window_left; Window_clip_right = window_right; Window_clip_top = window_top; Window_clip_bot = window_bottom; window_width = bp->bm_w; window_height = bp->bm_h; if (!Fix_recip_table_computed) init_fix_recip_table(); if (callclose) { callclose=0; atexit(free_ypointers); } } // ------------------------------------------------------------------------------------- // VARIABLES // ------------------------------------------------------------------------------------- // Returns number preceding val modulo modulus. // prevmod(3,4) = 2 // prevmod(0,4) = 3 int prevmod(int val,int modulus) { if (val > 0) return val-1; else return modulus-1; // return (val + modulus - 1) % modulus; } // Returns number succeeding val modulo modulus. // succmod(3,4) = 0 // succmod(0,4) = 1 int succmod(int val,int modulus) { if (val < modulus-1) return val+1; else return 0; // return (val + 1) % modulus; } // ------------------------------------------------------------------------------------- // Select topmost vertex (minimum y coordinate) and bottommost (maximum y coordinate) in // texture map. If either is part of a horizontal edge, then select leftmost vertex for // top, rightmost vertex for bottom. // Important: Vertex is selected with integer precision. So, if there are vertices at // (0.0,0.7) and (0.5,0.3), the first vertex is selected, because they y coordinates are // considered the same, so the smaller x is favored. // Parameters: // nv number of vertices // v3d pointer to 3d vertices containing u,v,x2d,y2d coordinates // Results in: // *min_y_ind // *max_y_ind // ------------------------------------------------------------------------------------- void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind) { int i; int min_y,max_y; int min_y_ind; int original_vrt; fix min_x; // Scan all vertices, set min_y_ind to vertex with smallest y coordinate. min_y = f2i(t->verts[0].y2d); max_y = min_y; min_y_ind = 0; min_x = f2i(t->verts[0].x2d); *bottom_y_ind = 0; for (i=1; inv; i++) { if (f2i(t->verts[i].y2d) < min_y) { min_y = f2i(t->verts[i].y2d); min_y_ind = i; min_x = f2i(t->verts[i].x2d); } else if (f2i(t->verts[i].y2d) == min_y) { if (f2i(t->verts[i].x2d) < min_x) { min_y_ind = i; min_x = f2i(t->verts[i].x2d); } } if (f2i(t->verts[i].y2d) > max_y) { max_y = f2i(t->verts[i].y2d); *bottom_y_ind = i; } } //--removed mk, 11/27/94-- // Check for a non-upright-hourglass polygon and fix, if necessary, by bashing a y coordinate. //--removed mk, 11/27/94-- // min_y_ind = index of minimum y coordinate, *bottom_y_ind = index of maximum y coordinate //--removed mk, 11/27/94--{ //--removed mk, 11/27/94-- int max_temp, min_temp; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- max_temp = *bottom_y_ind; //--removed mk, 11/27/94-- if (*bottom_y_ind < min_y_ind) //--removed mk, 11/27/94-- max_temp += t->nv; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- for (i=min_y_ind; iverts[i%t->nv].y2d) > f2i(t->verts[(i+1)%t->nv].y2d)) { //--removed mk, 11/27/94-- Int3(); //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- min_temp = min_y_ind; //--removed mk, 11/27/94-- if (min_y_ind < *bottom_y_ind) //--removed mk, 11/27/94-- min_temp += t->nv; //--removed mk, 11/27/94-- //--removed mk, 11/27/94-- for (i=*bottom_y_ind; iverts[i%t->nv].y2d) < f2i(t->verts[(i+1)%t->nv].y2d)) { //--removed mk, 11/27/94-- Int3(); //--removed mk, 11/27/94-- t->verts[(i+1)%t->nv].y2d = t->verts[i%t->nv].y2d; //--removed mk, 11/27/94-- } //--removed mk, 11/27/94-- } //--removed mk, 11/27/94--} // Set "vertex left top", etc. based on vertex with topmost y coordinate *vlt = min_y_ind; *vrt = *vlt; *vlb = prevmod(*vlt,t->nv); *vrb = succmod(*vrt,t->nv); // If right edge is horizontal, then advance along polygon bound until it no longer is or until all // vertices have been examined. // (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.) original_vrt = *vrt; while (f2i(t->verts[*vrt].y2d) == f2i(t->verts[*vrb].y2d)) { if (succmod(*vrt,t->nv) == original_vrt) { break; } *vrt = succmod(*vrt,t->nv); *vrb = succmod(*vrt,t->nv); } } // ------------------------------------------------------------------------------------- // Returns dx/dy given two vertices. // If dy == 0, returns 0.0 // ------------------------------------------------------------------------------------- //--fix compute_dx_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex) //--{ //-- int dy; //-- //-- // compute delta x with respect to y for any edge //-- dy = f2i(t->verts[bottom_vertex].y2d - t->verts[top_vertex].y2d) + 1; //-- if (dy) //-- return (t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d) / dy; //-- else //-- return 0; //-- //--} fix compute_du_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].u - t->verts[top_vertex].u, recip_dy); } fix compute_dv_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].v - t->verts[top_vertex].v, recip_dy); } fix compute_dl_dy_lin(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].l - t->verts[top_vertex].l, recip_dy); } fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].x2d - t->verts[top_vertex].x2d, recip_dy); } fix compute_du_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(fixmul(t->verts[bottom_vertex].u,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].u,t->verts[top_vertex].z), recip_dy); } fix compute_dv_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(fixmul(t->verts[bottom_vertex].v,t->verts[bottom_vertex].z) - fixmul(t->verts[top_vertex].v,t->verts[top_vertex].z), recip_dy); } fix compute_dz_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy) { return fixmul(t->verts[bottom_vertex].z - t->verts[top_vertex].z, recip_dy); } int Skip_short_flag=0; // ------------------------------------------------------------------------------------- // Texture map current scanline in perspective. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix zleft, fix zright, fix lleft, fix lright) { fix dx,recip_dx; fx_xright = f2i(xright); //edited 06/27/99 Matt Mueller - moved these tests up from within the switch so as not to do a bunch of needless calculations when we are just gonna return anyway. Slight fps boost? if (fx_xright < Window_clip_left) return; fx_xleft = f2i(xleft); if (fx_xleft > Window_clip_right) return; //end edit -MM dx = fx_xright - fx_xleft; if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; fx_u = uleft; fx_v = vleft; fx_z = zleft; fx_du_dx = fixmul(uright - uleft,recip_dx); fx_dv_dx = fixmul(vright - vleft,recip_dx); fx_dz_dx = fixmul(zright - zleft,recip_dx); fx_y = y; pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: //added 05/17/99 Matt Mueller - prevent writing before the buffer if ((fx_y == 0) && (fx_xleft < 0)) fx_xleft = 0; //end addition -MM if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; cur_tmap_scanline_per(); break; case 1: { fix mul_thing; if (lleft < 0) lleft = 0; if (lright < 0) lright = 0; if (lleft > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lleft = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); if (lright > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) lright = (NUM_LIGHTING_LEVELS*F1_0-F1_0/2); fx_l = lleft; fx_dl_dx = fixmul(lright - lleft,recip_dx); // This is a pretty ugly hack to prevent lighting overflows. mul_thing = dx * fx_dl_dx; if (lleft + mul_thing < 0) fx_dl_dx += 12; else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) fx_dl_dx -= 12; //added 05/17/99 Matt Mueller - prevent writing before the buffer if ((fx_y == 0) && (fx_xleft < 0)) fx_xleft = 0; //end addition -MM if (fx_xright > Window_clip_right) fx_xright = Window_clip_right; cur_tmap_scanline_per(); break; } case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); tmap_flat_color = 1; cur_tmap_scanline_flat(); #else Int3(); // Illegal, called an editor only routine! #endif break; } } int Do_vertical_scan=0; int Break_on_flat=0; // ------------------------------------------------------------------------------------- // Render a texture map with lighting using perspective interpolation in inner and outer loops. // ------------------------------------------------------------------------------------- void ntexture_map_lighted(grs_bitmap *srcb, g3ds_tmap *t) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; fix du_dy_left,du_dy_right; fix dv_dy_left,dv_dy_right; fix dz_dy_left,dz_dy_right; fix dl_dy_left,dl_dy_right; fix recip_dyl, recip_dyr; int max_y_vertex; fix xleft,xright,uleft,vleft,uright,vright,zleft,zright,lleft,lright; int next_break_left, next_break_right; g3ds_vertex *v3d; //remove stupid warnings in compile dl_dy_left = F1_0; dl_dy_right = F1_0; lleft = F1_0; lright = F1_0; v3d = t->verts; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); if (topy > Window_clip_bot) return; if (boty > Window_clip_bot) boty = Window_clip_bot; // Set amount to change x coordinate for each advance to next scanline. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyl = fix_recip[dy]; else recip_dyl = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); du_dy_left = compute_du_dy(t,vlt,vlb, recip_dyl); dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dyl); dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dyl); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyr = fix_recip[dy]; else recip_dyr = F1_0/dy; du_dy_right = compute_du_dy(t,vrt,vrb, recip_dyr); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dyr); dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dyr); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); lleft = v3d[vlt].l; lright = v3d[vrt].l; } // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; zleft = v3d[vlt].z; zright = v3d[vrt].z; uleft = fixmul(v3d[vlt].u,zleft); uright = fixmul(v3d[vrt].u,zright); vleft = fixmul(v3d[vlt].v,zleft); vright = fixmul(v3d[vrt].v,zright); // scan all rows in texture map from top through first break. next_break_left = f2i(v3d[vlb].y2d); next_break_right = f2i(v3d[vrb].y2d); for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == next_break_left) { fix recip_dy; // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } next_break_left = f2i(v3d[vlb].y2d); dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; zleft = v3d[vlt].z; uleft = fixmul(v3d[vlt].u,zleft); vleft = fixmul(v3d[vlt].v,zleft); lleft = v3d[vlt].l; du_dy_left = compute_du_dy(t,vlt,vlb, recip_dy); dv_dy_left = compute_dv_dy(t,vlt,vlb, recip_dy); dz_dy_left = compute_dz_dy(t,vlt,vlb, recip_dy); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); lleft = v3d[vlt].l; } } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == next_break_right) { fix recip_dy; while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } next_break_right = f2i(v3d[vrb].y2d); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; zright = v3d[vrt].z; uright = fixmul(v3d[vrt].u,zright); vright = fixmul(v3d[vrt].v,zright); du_dy_right = compute_du_dy(t,vrt,vrb, recip_dy); dv_dy_right = compute_dv_dy(t,vrt,vrb, recip_dy); dz_dy_right = compute_dz_dy(t,vrt,vrb, recip_dy); if (Lighting_enabled) { dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); lright = v3d[vrt].l; } } if (Lighting_enabled) { if (y >= Window_clip_top) ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); lleft += dl_dy_left; lright += dl_dy_right; } else if (y >= Window_clip_top) ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); uleft += du_dy_left; vleft += dv_dy_left; uright += du_dy_right; vright += dv_dy_right; xleft += dx_dy_left; xright += dx_dy_right; zleft += dz_dy_left; zright += dz_dy_right; } // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. ntmap_scanline_lighted(srcb,y,xleft,xright,uleft,uright,vleft,vright,zleft,zright,lleft,lright); } // ------------------------------------------------------------------------------------- // Texture map current scanline using linear interpolation. // ------------------------------------------------------------------------------------- void ntmap_scanline_lighted_linear(grs_bitmap *srcb, int y, fix xleft, fix xright, fix uleft, fix uright, fix vleft, fix vright, fix lleft, fix lright) { fix dx,recip_dx,du_dx,dv_dx,dl_dx; dx = f2i(xright) - f2i(xleft); if ((dx < 0) || (xright < 0) || (xleft > xright)) // the (xleft > xright) term is not redundant with (dx < 0) because dx is computed using integers return; // setup to call assembler scanline renderer if (dx < FIX_RECIP_TABLE_SIZE) recip_dx = fix_recip[dx]; else recip_dx = F1_0/dx; du_dx = fixmul(uright - uleft,recip_dx); dv_dx = fixmul(vright - vleft,recip_dx); fx_u = uleft; fx_v = vleft; fx_du_dx = du_dx; fx_dv_dx = dv_dx; fx_y = y; fx_xright = f2i(xright); fx_xleft = f2i(xleft); pixptr = srcb->bm_data; switch (Lighting_enabled) { case 0: //added 07/11/99 adb - prevent writing before the buffer if (fx_xleft < 0) fx_xleft = 0; //end addition -adb cur_tmap_scanline_lin_nolight(); break; case 1: if (lleft < F1_0/2) lleft = F1_0/2; if (lright < F1_0/2) lright = F1_0/2; if (lleft > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lleft = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; if (lright > MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS) lright = MAX_LIGHTING_VALUE*NUM_LIGHTING_LEVELS; //added 07/11/99 adb - prevent writing before the buffer if (fx_xleft < 0) fx_xleft = 0; //end addition -adb { fix mul_thing; fx_l = lleft; fx_dl_dx = fixmul(lright - lleft,recip_dx); // This is a pretty ugly hack to prevent lighting overflows. mul_thing = dx * fx_dl_dx; if (lleft + mul_thing < 0) fx_dl_dx += 12; else if (lleft + mul_thing > (NUM_LIGHTING_LEVELS*F1_0-F1_0/2)) fx_dl_dx -= 12; } fx_l = lleft; dl_dx = fixmul(lright - lleft,recip_dx); fx_dl_dx = dl_dx; cur_tmap_scanline_lin(); break; case 2: #ifdef EDITOR_TMAP fx_xright = f2i(xright); fx_xleft = f2i(xleft); tmap_flat_color = 1; cur_tmap_scanline_flat(); #else Int3(); // Illegal, called an editor only routine! #endif break; } } // ------------------------------------------------------------------------------------- // Render a texture map with lighting using perspective interpolation in inner and outer loops. // ------------------------------------------------------------------------------------- void ntexture_map_lighted_linear(grs_bitmap *srcb, g3ds_tmap *t) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; fix du_dy_left,du_dy_right; fix dv_dy_left,dv_dy_right; fix dl_dy_left,dl_dy_right; int max_y_vertex; fix xleft,xright,uleft,vleft,uright,vright,lleft,lright; int next_break_left, next_break_right; fix recip_dyl, recip_dyr; g3ds_vertex *v3d; //remove stupid warnings in compile dl_dy_left = F1_0; dl_dy_right = F1_0; lleft = F1_0; lright = F1_0; v3d = t->verts; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); if (topy > Window_clip_bot) return; if (boty > Window_clip_bot) boty = Window_clip_bot; dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyl = fix_recip[dy]; else recip_dyl = F1_0/dy; dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dyr = fix_recip[dy]; else recip_dyr = F1_0/dy; // Set amount to change x coordinate for each advance to next scanline. dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dyl); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dyr); du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dyl); du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dyr); dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dyl); dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dyr); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dyl); dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dyr); lleft = v3d[vlt].l; lright = v3d[vrt].l; } // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; uleft = v3d[vlt].u; uright = v3d[vrt].u; vleft = v3d[vlt].v; vright = v3d[vrt].v; // scan all rows in texture map from top through first break. next_break_left = f2i(v3d[vlb].y2d); next_break_right = f2i(v3d[vrb].y2d); for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == next_break_left) { fix recip_dy; // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } next_break_left = f2i(v3d[vlb].y2d); dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; uleft = v3d[vlt].u; vleft = v3d[vlt].v; lleft = v3d[vlt].l; du_dy_left = compute_du_dy_lin(t,vlt,vlb, recip_dy); dv_dy_left = compute_dv_dy_lin(t,vlt,vlb, recip_dy); if (Lighting_enabled) { dl_dy_left = compute_dl_dy_lin(t,vlt,vlb, recip_dy); lleft = v3d[vlt].l; } } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == next_break_right) { fix recip_dy; while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; next_break_right = f2i(v3d[vrb].y2d); dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; uright = v3d[vrt].u; vright = v3d[vrt].v; du_dy_right = compute_du_dy_lin(t,vrt,vrb, recip_dy); dv_dy_right = compute_dv_dy_lin(t,vrt,vrb, recip_dy); if (Lighting_enabled) { dl_dy_right = compute_dl_dy_lin(t,vrt,vrb, recip_dy); lright = v3d[vrt].l; } } if (Lighting_enabled) { ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); lleft += dl_dy_left; lright += dl_dy_right; } else ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); uleft += du_dy_left; vleft += dv_dy_left; uright += du_dy_right; vright += dv_dy_right; xleft += dx_dy_left; xright += dx_dy_right; } // We can get lleft or lright out of bounds here because we compute dl_dy using fixed point values, // but we plot an integer number of scanlines, therefore doing an integer number of additions of the delta. ntmap_scanline_lighted_linear(srcb,y,xleft,xright,uleft,uright,vleft,vright,lleft,lright); } // fix DivNum = F1_0*12; // ------------------------------------------------------------------------------------- // Interface from Matt's data structures to Mike's texture mapper. // ------------------------------------------------------------------------------------- void draw_tmap(grs_bitmap *bp,int nverts,g3s_point **vertbuf) { int i; // These variables are used in system which renders texture maps which lie on one scanline as a line. // fix div_numerator; int lighting_on_save = Lighting_on; Assert(nverts <= MAX_TMAP_VERTS); #ifdef USE_MULT_CODE if ( !divide_table_filled ) fill_divide_table(); #endif // -- now called from g3_start_frame -- init_interface_vars_to_assembler(); // If no transparency and seg depth is large, render as flat shaded. if ((Current_seg_depth > Max_linear_depth) && ((bp->bm_flags & 3) == 0)) { draw_tmap_flat(bp, nverts, vertbuf); return; } if ( bp->bm_flags & BM_FLAG_RLE ) bp = rle_expand_texture( bp ); // Expand if rle'd Transparency_on = bp->bm_flags & BM_FLAG_TRANSPARENT; if (bp->bm_flags & BM_FLAG_NO_LIGHTING) Lighting_on = 0; // Setup texture map in Tmap1 Tmap1.nv = nverts; // Initialize number of vertices // div_numerator = DivNum; //f1_0*3; for (i=0; ix2d = vp->p3_sx; tvp->y2d = vp->p3_sy; // Check for overflow on fixdiv. Will overflow on vp->z <= something small. Allow only as low as 256. if (vp->p3_z < 256) { vp->p3_z = 256; // Int3(); // we would overflow if we divided! } tvp->z = fixdiv(F1_0*12, vp->p3_z); tvp->u = vp->p3_u << 6; //* bp->bm_w; tvp->v = vp->p3_v << 6; //* bp->bm_h; Assert(Lighting_on < 3); if (Lighting_on) tvp->l = vp->p3_l * NUM_LIGHTING_LEVELS; } Lighting_enabled = Lighting_on; // Now, call my texture mapper. if (Lighting_on) { switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective case 0: // choose best interpolation per2_flag = 1; if (Current_seg_depth > Max_perspective_depth) ntexture_map_lighted_linear(bp, &Tmap1); else ntexture_map_lighted(bp, &Tmap1); break; case 1: // linear interpolation per2_flag = 1; ntexture_map_lighted_linear(bp, &Tmap1); break; case 2: // perspective every 8th pixel interpolation per2_flag = 1; ntexture_map_lighted(bp, &Tmap1); break; case 3: // perspective every pixel interpolation per2_flag = 0; // this hack means do divide every pixel ntexture_map_lighted(bp, &Tmap1); break; default: Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3 } } else { switch (Interpolation_method) { // 0 = choose, 1 = linear, 2 = /8 perspective, 3 = full perspective case 0: // choose best interpolation per2_flag = 1; if (Current_seg_depth > Max_perspective_depth) ntexture_map_lighted_linear(bp, &Tmap1); else ntexture_map_lighted(bp, &Tmap1); break; case 1: // linear interpolation per2_flag = 1; ntexture_map_lighted_linear(bp, &Tmap1); break; case 2: // perspective every 8th pixel interpolation per2_flag = 1; ntexture_map_lighted(bp, &Tmap1); break; case 3: // perspective every pixel interpolation per2_flag = 0; // this hack means do divide every pixel ntexture_map_lighted(bp, &Tmap1); break; default: Assert(0); // Illegal value for Interpolation_method, must be 0,1,2,3 } } Lighting_on = lighting_on_save; } dxx-rebirth-0.58.1-d1x/texmap/scanline.c000066400000000000000000000713361217717257200200220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines to draw the texture mapped scanlines. * */ #include #include #include #include #include #include "maths.h" #include "gr.h" #include "grdef.h" #include "texmap.h" #include "texmapl.h" #include "scanline.h" #include "strutil.h" #include "dxxerror.h" void c_tmap_scanline_flat() { ubyte *dest; int x, index = fx_xleft + (bytes_per_row * fx_y ); dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y ) ); for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = tmap_flat_color; } // memset(dest,tmap_flat_color,fx_xright-fx_xleft+1); } void c_tmap_scanline_shaded() { int fade; ubyte *dest, tmp; int x, index = fx_xleft + (bytes_per_row * fx_y ); dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); fade = tmap_flat_shade_value<<8; for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; tmp = *dest; *dest++ = gr_fade_table[ fade |(tmp)]; } } void c_tmap_scanline_lin_nolight() { ubyte *dest; uint c; int x, index = fx_xleft + (bytes_per_row * fx_y ); fix u,v,dudx, dvdx; u = fx_u; v = fx_v*64; dudx = fx_du_dx; dvdx = fx_dv_dx*64; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = (uint)pixptr[ (f2i(v)&(64*63)) + (f2i(u)&63) ]; u += dudx; v += dvdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint)pixptr[ (f2i(v)&(64*63)) + (f2i(u)&63) ]; if ( c!=255) *dest = c; dest++; u += dudx; v += dvdx; } } } #if 1 void c_tmap_scanline_lin() { ubyte *dest; uint c; int x, j, index = fx_xleft + (bytes_per_row * fx_y); fix u,v,l,dudx, dvdx, dldx; u = fx_u; v = fx_v*64; dudx = fx_du_dx; dvdx = fx_dv_dx*64; l = fx_l>>8; dldx = fx_dl_dx/256; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { ubyte* pixPtrLocalCopy = pixptr; ubyte* fadeTableLocalCopy = gr_fade_table; unsigned long destlong; x = fx_xright-fx_xleft+1; if ((j = (unsigned long) dest & 3) != 0) { j = 4 - j; if (j > x) j = x; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; x--; j--; } } j &= ~3; while (j > 0) { //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong = (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ] << 24; //end edit -MM l += dldx; u += dudx; v += dvdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ] << 16; //end edit -MM l += dldx; u += dudx; v += dvdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ] << 8; //end edit -MM l += dldx; u += dudx; v += dvdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; *((unsigned long *) dest) = destlong; dest += 4; x -= 4; j -= 4; index += 4; if (index+4 >= SWIDTH*SHEIGHT) return; } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint) pixPtrLocalCopy[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint)pixptr[ (f2i(v)&(64*63)) + (f2i(u)&63) ]; if ( c!=TRANSPARENCY_COLOR) //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest = gr_fade_table[ (l&(0x7f00)) + c ]; //end edit -MM dest++; l += dldx; u += dudx; v += dvdx; } } } #else void c_tmap_scanline_lin() { ubyte *dest; uint c; int x; fix u,v,l,dudx, dvdx, dldx; u = fx_u; v = fx_v*64; dudx = fx_du_dx; dvdx = fx_dv_dx*64; l = fx_l>>8; dldx = fx_dl_dx/256; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = gr_fade_table[ (l&(0x7f00)) + (uint)pixptr[ (f2i(v)&(64*63)) + (f2i(u)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { c = (uint)pixptr[ (f2i(v)&(64*63)) + (f2i(u)&63) ]; if ( c!=255) //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest = gr_fade_table[ (l&(0x7f00)) + c ]; //end edit -MM dest++; l += dldx; u += dudx; v += dvdx; } } } #endif // Used for energy centers. See comments for c_tmap_scanline_per(). void c_fp_tmap_scanline_per_nolight() { ubyte *dest; uint c; int x, j, index = fx_xleft + (bytes_per_row * fx_y); double u, v, z, dudx, dvdx, dzdx, rec_z; u_int64_t destlong; u = f2db(fx_u); v = f2db(fx_v) * 64.0; z = f2db(fx_z); dudx = f2db(fx_du_dx); dvdx = f2db(fx_dv_dx) * 64.0; dzdx = f2db(fx_dz_dx); rec_z = 1.0 / z; dest = (ubyte *) (write_buffer + fx_xleft + (bytes_per_row * fx_y)); x = fx_xright - fx_xleft + 1; if (!Transparency_on) { if (x >= 8) { if ((j = (size_t) dest & 7) != 0) { j = 8 - j; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; x--; j--; } } while (j >= 8) { destlong = (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 8; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 16; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 24; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 32; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 40; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 48; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)] << 56; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; *((u_int64_t *) dest) = destlong; dest += 8; x -= 8; j -= 8; index +=8; if (index+8 >= SWIDTH*SHEIGHT) return; } } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = (u_int64_t) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; } } else { x = fx_xright - fx_xleft + 1; if (x >= 8) { if ((j = (size_t) dest & 7) != 0) { j = 8 - j; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) *dest = c; dest++; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; x--; j--; } } j = x; while (j >= 8) { destlong = *((u_int64_t *) dest); c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~(u_int64_t)0xFF; destlong |= (u_int64_t) c; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 8); destlong |= (u_int64_t) c << 8; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 16); destlong |= (u_int64_t) c << 16; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 24); destlong |= (u_int64_t) c << 24; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 32); destlong |= (u_int64_t) c << 32; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 40); destlong |= (u_int64_t) c << 40; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 48); destlong |= (u_int64_t) c << 48; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 56); destlong |= (u_int64_t) c << 56; } u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; *((u_int64_t *) dest) = destlong; dest += 8; x -= 8; j -= 8; index += 8; if (index+8 >= SWIDTH*SHEIGHT) return; } } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) *dest = c; dest++; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; } } } void c_tmap_scanline_per_nolight() { ubyte *dest; uint c; int x, index = fx_xleft + (bytes_per_row * fx_y); fix u,v,z,dudx, dvdx, dzdx; u = fx_u; v = fx_v*64; z = fx_z; dudx = fx_du_dx; dvdx = fx_dv_dx*64; dzdx = fx_dz_dx; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = (uint)pixptr[ ( (v/z)&(64*63) ) + ((u/z)&63) ]; u += dudx; v += dvdx; z += dzdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint)pixptr[ ( (v/z)&(64*63) ) + ((u/z)&63) ]; if ( c!=255) *dest = c; dest++; u += dudx; v += dvdx; z += dzdx; } } } // This texture mapper uses floating point extensively and writes 8 pixels at once, so it likely works // best on 64 bit RISC processors. // WARNING: it is not endian clean. For big endian, reverse the shift counts in the unrolled loops. I // have no means to test that, so I didn't try it. Please tell me if you get this to work on a big // endian machine. // If you're using an Alpha, use the Compaq compiler for this file for quite some fps more. // Unfortunately, it won't compile the whole source, so simply compile everything, change the // compiler to ccc, remove scanline.o and compile again. // Please send comments/suggestions to falk.hueffner@student.uni-tuebingen.de. void c_fp_tmap_scanline_per() { ubyte *dest; uint c; int x, j, index = fx_xleft + (bytes_per_row * fx_y); double u, v, z, l, dudx, dvdx, dzdx, dldx, rec_z; u_int64_t destlong; u = f2db(fx_u); v = f2db(fx_v) * 64.0; z = f2db(fx_z); l = f2db(fx_l); dudx = f2db(fx_du_dx); dvdx = f2db(fx_dv_dx) * 64.0; dzdx = f2db(fx_dz_dx); dldx = f2db(fx_dl_dx); rec_z = 1.0 / z; // gcc 2.95.2 is won't do this optimization itself dest = (ubyte *) (write_buffer + fx_xleft + (bytes_per_row * fx_y)); x = fx_xright - fx_xleft + 1; if (!Transparency_on) { if (x >= 8) { if ((j = (size_t) dest & 7) != 0) { j = 8 - j; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]]; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; x--; j--; } } j = x; while (j >= 8) { destlong = (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]]; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 8; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 16; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 24; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 32; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 40; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 48; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]] << 56; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; *((u_int64_t *) dest) = destlong; dest += 8; x -= 8; j -= 8; index += 8; if (index+8 >= SWIDTH*SHEIGHT) return; } } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = gr_fade_table[((int) fabs(l)) * 256 + (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]]; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; } } else { if (x >= 8) { if ((j = (size_t) dest & 7) != 0) { j = 8 - j; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) *dest = gr_fade_table[((int) fabs(l)) * 256 + c]; dest++; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; x--; j--; } } j = x; while (j >= 8) { destlong = *((u_int64_t *) dest); c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~(u_int64_t)0xFF; destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c]; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 8); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 8; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 16); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 16; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 24); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 24; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 32); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 32; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 40); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 40; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 48); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 48; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) { destlong &= ~((u_int64_t)0xFF << 56); destlong |= (u_int64_t) gr_fade_table[((int) fabs(l)) * 256 + c] << 56; } l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; *((u_int64_t *) dest) = destlong; dest += 8; x -= 8; j -= 8; index += 8; if (index+8 >= SWIDTH*SHEIGHT) return; } } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint) pixptr[(((int) (v * rec_z)) & (64 * 63)) + (((int) (u * rec_z)) & 63)]; if (c != 255) *dest = gr_fade_table[((int) fabs(l)) * 256 + c]; dest++; l += dldx; u += dudx; v += dvdx; z += dzdx; rec_z = 1.0 / z; } } } #if 1 // note the unrolling loop is broken. It is never called, and uses big endian. -- FH void c_tmap_scanline_per() { ubyte *dest; uint c; int x, j, index = fx_xleft + (bytes_per_row * fx_y); fix l,u,v,z; fix dudx, dvdx, dzdx, dldx; u = fx_u; v = fx_v*64; z = fx_z; dudx = fx_du_dx; dvdx = fx_dv_dx*64; dzdx = fx_dz_dx; l = fx_l>>8; dldx = fx_dl_dx/256; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { ubyte* pixPtrLocalCopy = pixptr; ubyte* fadeTableLocalCopy = gr_fade_table; unsigned long destlong; x = fx_xright-fx_xleft+1; // x = number of pixels in scanline if ((j = (unsigned long) dest & 3) != 0) { j = 4 - j; if (j > x) j = x; while (j > 0) { if (++index >= SWIDTH*SHEIGHT) return; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; x--; j--; } } j &= ~3; while (j > 0) { //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong = (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ] << 24; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ] << 16; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ] << 8; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches destlong |= (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; *((unsigned long *) dest) = destlong; dest += 4; x -= 4; j -= 4; index += 4; if (index+4 >= SWIDTH*SHEIGHT) return; } while (x-- > 0) { if (++index >= SWIDTH*SHEIGHT) return; //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = (unsigned long) fadeTableLocalCopy[ (l&(0x7f00)) + (uint)pixPtrLocalCopy[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint)pixptr[ ( (v/z)&(64*63) ) + ((u/z)&63) ]; if ( c!=TRANSPARENCY_COLOR) *dest = gr_fade_table[ (l&(0x7f00)) + c ]; dest++; l += dldx; u += dudx; v += dvdx; z += dzdx; } } } #else void c_tmap_scanline_per() { ubyte *dest; uint c; int x; fix u,v,z,l,dudx, dvdx, dzdx, dldx; u = fx_u; v = fx_v*64; z = fx_z; dudx = fx_du_dx; dvdx = fx_dv_dx*64; dzdx = fx_dz_dx; l = fx_l>>8; dldx = fx_dl_dx/256; dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest++ = gr_fade_table[ (l&(0x7f00)) + (uint)pixptr[ ( (v/z)&(64*63) ) + ((u/z)&63) ] ]; //end edit -MM l += dldx; u += dudx; v += dvdx; z += dzdx; } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { c = (uint)pixptr[ ( (v/z)&(64*63) ) + ((u/z)&63) ]; if ( c!=255) //edited 05/18/99 Matt Mueller - changed from 0xff00 to 0x7f00 to fix glitches *dest = gr_fade_table[ (l&(0x7f00)) + c ]; //end edit -MM dest++; l += dldx; u += dudx; v += dvdx; z += dzdx; } } } #endif void c_tmap_scanline_quad() { ubyte *dest; uint c; int x, index = fx_xleft + (bytes_per_row * fx_y); fix u,v,l,dudx, dvdx, dldx; // Quadratic setup stuff: fix a1, a2, b1, b2, dudx1, dvdx1; fix u0 = fx_u; fix u2 = fx_u + fx_du_dx*(fx_xright-fx_xleft+1); // This just needs to be uright from outer loop fix v0 = fx_v; fix v2 = fx_v + fx_dv_dx*(fx_xright-fx_xleft+1); // This just needs to be vright from outer loop fix w0 = fx_z; fix w2 = fx_z + fx_dz_dx*(fx_xright-fx_xleft+1); // This just needs to be zright from outer loop fix u1 = fixdiv((u0+u2),(w0+w2)); fix v1 = fixdiv((v0+v2),(w0+w2)); int dx = fx_xright-fx_xleft+1; u0 = fixdiv( u0, w0 ); // Divide Z out. This should be in outer loop v0 = fixdiv( v0, w0 ); // Divide Z out. This should be in outer loop u2 = fixdiv( u2, w2 ); // Divide Z out. This should be in outer loop v2 = fixdiv( v2, w2 ); // Divide Z out. This should be in outer loop a1 = (-3*u0+4*u1-u2)/dx; b1 = (-3*v0+4*v1-v2)/dx; a2 = (2*(u0-2*u1+u2))/(dx*dx); b2 = (2*(v0-2*v1+v2))/(dx*dx); dudx = a1 + a2; dvdx = b1 + b2; dudx1 = 2*a2; dvdx1 = 2*b2; u = u0; v = v0; // Normal lighting setup l = fx_l>>8; dldx = fx_dl_dx>>8; // Normal destination pointer setup dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y) ); if (!Transparency_on) { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; *dest++ = gr_fade_table[ (l&(0xff00)) + (uint)pixptr[ (f2i(v)&63)*64 + (f2i(u)&63) ] ]; l += dldx; u += dudx; v += dvdx; dudx += dudx1; // Extra add for quadratic! dvdx += dvdx1; // Extra add for quadratic! } } else { for (x= fx_xright-fx_xleft+1 ; x > 0; --x ) { if (++index >= SWIDTH*SHEIGHT) return; c = (uint)pixptr[ (f2i(v)&63)*64 + (f2i(u)&63) ]; if ( c!=255) *dest = gr_fade_table[ (l&(0xff00)) + c ]; dest++; l += dldx; u += dudx; v += dvdx; dudx += dudx1; // Extra add for quadratic! dvdx += dvdx1; // Extra add for quadratic! } } } void (*cur_tmap_scanline_per)(void); void (*cur_tmap_scanline_per_nolight)(void); void (*cur_tmap_scanline_lin)(void); void (*cur_tmap_scanline_lin_nolight)(void); void (*cur_tmap_scanline_flat)(void); void (*cur_tmap_scanline_shaded)(void); //runtime selection of optimized tmappers. 12/07/99 Matthew Mueller //the reason I did it this way rather than having a *tmap_funcs that then points to a c_tmap or fp_tmap struct thats already filled in, is to avoid a second pointer dereference. void select_tmap(char *type) { if (!type) { #if !defined(NO_ASM) && !defined(OGL) select_tmap("i386"); #elif defined(macintosh) && !defined(OGL) select_tmap("ppc"); #else select_tmap("c"); #endif return; } #if !defined(NO_ASM) && !defined(OGL) if (d_stricmp(type, "i386")==0) { cur_tmap_scanline_per=asm_tmap_scanline_per; cur_tmap_scanline_per_nolight=asm_tmap_scanline_per; cur_tmap_scanline_lin=asm_tmap_scanline_lin_lighted; cur_tmap_scanline_lin_nolight=asm_tmap_scanline_lin; cur_tmap_scanline_flat=asm_tmap_scanline_flat; cur_tmap_scanline_shaded=asm_tmap_scanline_shaded; } else #elif defined(macintosh) && !defined(OGL) if (d_stricmp(type,"ppc")==0){ cur_tmap_scanline_per=asm_tmap_scanline_per; cur_tmap_scanline_per_nolight=asm_tmap_scanline_per; cur_tmap_scanline_lin=c_tmap_scanline_lin; cur_tmap_scanline_lin_nolight=c_tmap_scanline_lin_nolight; cur_tmap_scanline_flat=c_tmap_scanline_flat; cur_tmap_scanline_shaded=c_tmap_scanline_shaded; } else #endif if (d_stricmp(type,"fp")==0){ cur_tmap_scanline_per=c_fp_tmap_scanline_per; cur_tmap_scanline_per_nolight=c_fp_tmap_scanline_per_nolight; cur_tmap_scanline_lin=c_tmap_scanline_lin; cur_tmap_scanline_lin_nolight=c_tmap_scanline_lin_nolight; cur_tmap_scanline_flat=c_tmap_scanline_flat; cur_tmap_scanline_shaded=c_tmap_scanline_shaded; } else if (d_stricmp(type,"quad")==0){ cur_tmap_scanline_per=c_tmap_scanline_quad; cur_tmap_scanline_per_nolight=c_tmap_scanline_per_nolight; cur_tmap_scanline_lin=c_tmap_scanline_lin; cur_tmap_scanline_lin_nolight=c_tmap_scanline_lin_nolight; cur_tmap_scanline_flat=c_tmap_scanline_flat; cur_tmap_scanline_shaded=c_tmap_scanline_shaded; } else { cur_tmap_scanline_per=c_tmap_scanline_per; cur_tmap_scanline_per_nolight=c_tmap_scanline_per_nolight; cur_tmap_scanline_lin=c_tmap_scanline_lin; cur_tmap_scanline_lin_nolight=c_tmap_scanline_lin_nolight; cur_tmap_scanline_flat=c_tmap_scanline_flat; cur_tmap_scanline_shaded=c_tmap_scanline_shaded; } } dxx-rebirth-0.58.1-d1x/texmap/scanline.h000066400000000000000000000040551217717257200200210ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/scanline.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:45:56 $ * * Prototypes for C versions of texture mapped scanlines. * * $Log: scanline.h,v $ * Revision 1.1.1.1 2006/03/17 19:45:56 zicodxx * initial import * * Revision 1.2 1999/12/08 01:03:51 donut * allow runtime selection of tmap routines * * Revision 1.1.1.1 1999/06/14 22:14:10 donut * Import of d1x 1.37 source. * * Revision 1.2 1995/02/20 18:23:40 john * Added new module for C versions of inner loops. * * Revision 1.1 1995/02/20 17:44:16 john * Initial revision * * */ #ifndef _SCANLINE_H #define _SCANLINE_H extern void c_tmap_scanline_per(); extern void c_tmap_scanline_per_nolight(); extern void c_tmap_scanline_lin(); extern void c_tmap_scanline_lin_nolight(); extern void c_tmap_scanline_flat(); extern void c_tmap_scanline_shaded(); //typedef struct _tmap_scanline_funcs { extern void (*cur_tmap_scanline_per)(void); extern void (*cur_tmap_scanline_per_nolight)(void); extern void (*cur_tmap_scanline_lin)(void); extern void (*cur_tmap_scanline_lin_nolight)(void); extern void (*cur_tmap_scanline_flat)(void); extern void (*cur_tmap_scanline_shaded)(void); //} tmap_scanline_funcs; //extern tmap_scanline_funcs tmap_funcs; void select_tmap(char *type); #endif dxx-rebirth-0.58.1-d1x/texmap/texmapl.h000066400000000000000000000117551217717257200177040ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/texmapl.h,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:46:00 $ * * Local include file for texture mapper library -- NOT to be included by users. * * $Log: texmapl.h,v $ * Revision 1.1.1.1 2006/03/17 19:46:00 zicodxx * initial import * * Revision 1.2 1999/12/08 01:03:51 donut * allow runtime selection of tmap routines * * Revision 1.1.1.1 1999/06/14 22:14:11 donut * Import of d1x 1.37 source. * * Revision 1.14 1995/02/20 18:23:02 john * Put all the externs in the assembly modules into tmap_inc.asm. * Also, moved all the C versions of the inner loops into a new module, * scanline.c. * * Revision 1.13 1995/02/20 17:09:16 john * Added code so that you can build the tmapper with no assembly! * * Revision 1.12 1994/11/28 13:34:34 mike * optimizations. * * Revision 1.11 1994/11/12 16:41:27 mike * function prototype. * * Revision 1.10 1994/05/24 17:30:00 mike * Prototype fix_recip, asm_tmap_scanline_lin_v. * * Revision 1.9 1994/04/21 15:04:26 mike * Add prototype for texmapl.h * * Revision 1.8 1994/03/31 08:34:53 mike * *** empty log message *** * * Revision 1.7 1994/03/22 20:37:04 mike * *** empty log message *** * * Revision 1.6 1994/03/14 15:43:03 mike * streamline code. * * Revision 1.5 1994/01/31 15:43:18 mike * window_height, asm_tmap_scanline_lin_sky_v * * Revision 1.4 1994/01/21 21:12:27 mike * Prototype asm_tmap_scanline_lin_sky * * Revision 1.3 1994/01/14 14:01:45 mike * Add a bunch of variables. * * Revision 1.2 1993/11/22 10:25:11 mike * *** empty log message *** * * Revision 1.1 1993/09/08 17:29:13 mike * Initial revision * * */ // Local include file for texture map library. extern int prevmod(int val,int modulus); extern int succmod(int val,int modulus); extern void texture_map_flat(g3ds_tmap *t,int color); extern fix compute_dx_dy(g3ds_tmap *t, int top_vertex,int bottom_vertex, fix recip_dy); extern void compute_y_bounds(g3ds_tmap *t, int *vlt, int *vlb, int *vrt, int *vrb,int *bottom_y_ind); extern void asm_tmap_scanline_lin_v(void); extern int fx_y,fx_xleft,fx_xright,per2_flag; extern unsigned char tmap_flat_color; extern unsigned char *pixptr; // texture mapper scanline renderers extern void asm_tmap_scanline_per(void); extern void asm_pent_tmap_scanline_per(void); extern void asm_ppro_tmap_scanline_per(void); //extern void asm_tmap_scanline_per_doubled(void); extern void asm_tmap_scanline_lin(void); //extern void asm_tmap_scanline_lin_16(void); //extern void asm_tmap_scanline_per_16(void); extern void asm_tmap_scanline_lin_lighted(void); extern void asm_tmap_scanline_flat(void); extern void asm_tmap_scanline_shaded(void); //extern void asm_tmap_scanline_lin_lighted_k(void); //extern void asm_tmap_scanline_lin_rgb(void); //extern void asm_tmap_scanline_lin_rgb_16(void); //extern void asm_tmap_scanline_lin_rgb_16g(void); //extern void asm_tmap_scanline_lin_ld(void); //extern void asm_tmap_scanline_lin_sky(void); //extern void asm_tmap_scanline_lin_sky_v(void); extern fix compute_dx_dy_lin(g3ds_tmap *t,int vlt,int vlb, fix recip_dy); extern fix compute_dx_dy_lin(g3ds_tmap *t,int vrt,int vrb, fix recip_dy); extern fix compute_du_dy_lin(g3ds_tmap *t,int vlt,int vlb, fix recip_dy); extern fix compute_du_dy_lin(g3ds_tmap *t,int vrt,int vrb, fix recip_dy); extern fix compute_dv_dy_lin(g3ds_tmap *t,int vlt,int vlb, fix recip_dy); extern fix compute_dv_dy_lin(g3ds_tmap *t,int vrt,int vrb, fix recip_dy); // Interface variables to assembler code extern fix fx_u,fx_v,fx_z,fx_du_dx,fx_dv_dx,fx_dz_dx; extern fix fx_dl_dx,fx_l; extern int fx_r,fx_g,fx_b,fx_dr_dx,fx_dg_dx,fx_db_dx; extern unsigned char *pixptr; extern int bytes_per_row; extern unsigned char *write_buffer; extern int window_left; extern int window_right; extern int window_top; extern int window_bottom; extern int window_width; extern int window_height; extern int scan_doubling_flag; extern int linear_if_far_flag; extern int dither_intensity_lighting; extern int Interlacing_on; extern ubyte * tmap_flat_cthru_table; extern ubyte tmap_flat_color; extern ubyte tmap_flat_shade_value; extern fix fix_recip[]; extern void init_interface_vars_to_assembler(void); extern int prevmod(int val,int modulus); dxx-rebirth-0.58.1-d1x/texmap/tmap_flt.asm000077500000000000000000000102471217717257200203670ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmap_flt.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:45:59 $ ; ; Flat shader derived from texture mapper (kind of slow) ; ; $Log: tmap_flt.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:45:59 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:13:53 donut ; Import of d1x 1.37 source. ; ; Revision 1.10 1995/02/20 18:22:53 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.9 1995/02/20 17:08:51 john ; Added code so that you can build the tmapper with no assembly! ; ; Revision 1.8 1994/12/02 23:29:21 mike ; change jb/ja to jl/jg. ; ; Revision 1.7 1994/11/12 16:39:35 mike ; jae to ja. ; ; Revision 1.6 1994/08/09 11:27:53 john ; Added cthru mode. ; ; Revision 1.5 1994/07/08 17:43:11 john ; Added flat-shaded-zbuffered polygon. ; ; Revision 1.4 1994/04/08 16:25:43 mike ; optimize inner loop of flat shader. ; ; Revision 1.3 1994/03/31 08:34:20 mike ; Optimized (well, speeded-up) inner loop for tmap-based flat shader. ; ; Revision 1.2 1993/11/22 10:24:57 mike ; *** empty log message *** ; ; Revision 1.1 1993/09/08 17:29:46 mike ; Initial revision ; ; ; [BITS 32] global _asm_tmap_scanline_flat global asm_tmap_scanline_flat [SECTION .data] %include "tmap_inc.asm" [SECTION .text] ; -------------------------------------------------------------------------------------------------- ; Enter: ; _xleft fixed point left x coordinate ; _xright fixed point right x coordinate ; _y fixed point y coordinate ;**; _pixptr address of source pixel map ; for (x = (int) xleft; x <= (int) xright; x++) { ; _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63)); ; _setpixel(x,y); ; ; z += dz_dx; ; } align 4 _asm_tmap_scanline_flat: asm_tmap_scanline_flat: pusha ; Setup for loop: _loop_count iterations = (int) xright - (int) xleft ;**; esi source pixel pointer = pixptr ; edi initial row pointer = y*320+x ; set esi = pointer to start of texture map data ;** mov esi,_pixptr ; set edi = address of first pixel to modify mov edi,[_fx_y] cmp edi,[_window_bottom] ja near _none_to_do imul edi,[_bytes_per_row] mov eax,[_fx_xleft] test eax, eax jns eax_ok sub eax,eax eax_ok: add edi,eax add edi,[_write_buffer] ; set _loop_count = # of iterations mov eax,[_fx_xright] cmp eax,[_window_right] jl eax_ok1 mov eax,[_window_right] eax_ok1: cmp eax,[_window_left] jg eax_ok2 mov eax,[_window_left] eax_ok2: mov ebx,[_fx_xleft] sub eax,ebx js _none_to_do cmp eax,[_window_width] jbe _ok_to_do mov eax,[_window_width] dec eax _ok_to_do: mov ecx,eax ; edi = destination pixel pointer cmp dword [_tmap_flat_cthru_table], 0 jne do_flat_cthru mov al,[_tmap_flat_color] ; word align inc ecx test edi,1 je edi_even mov [edi],al inc edi dec ecx je _none_to_do edi_even: shr ecx,1 je _no_full_words mov ah,al rep stosw _no_full_words: adc ecx,ecx ; if cy set, then write one more pixel (ecx == 0) rep stosb ; write 0 or 1 pixel _none_to_do: popa ret do_flat_cthru: mov esi, [_tmap_flat_cthru_table] xor eax, eax cmp ecx, 0 je _none_to_do ; edi = dest, esi = table, ecx = count flat_cthru_loop: mov al, [edi] ; get already drawn pixel mov al, [eax+esi] ; xlat thru cthru table mov [edi],al ; write it inc edi dec ecx jnz flat_cthru_loop popa ret dxx-rebirth-0.58.1-d1x/texmap/tmap_inc.asm000077500000000000000000000120411217717257200203450ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmap_inc.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:46:06 $ ; ; Mike's include file for the texture mapper library. ; ; $Log: tmap_inc.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:46:06 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:13:53 donut ; Import of d1x 1.37 source. ; ; Revision 1.10 1995/02/20 18:22:52 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.9 1994/12/02 23:29:45 mike ; Add y_pointers. ; ; Revision 1.8 1994/11/12 16:39:36 mike ; jae to ja. ; ; Revision 1.7 1994/10/26 23:27:39 john ; Took out references to gr_inverse_table. ; ; Revision 1.6 1994/10/26 23:21:55 mike ; kill unused stuff. ; ; Revision 1.5 1994/07/27 18:39:20 john ; Took out references to blend table ; ; Revision 1.4 1994/01/31 15:40:17 mike ; Add window_height. ; ; Revision 1.3 1993/12/07 12:27:48 john ; Moved bmd_palette to gr_palette ; ; Revision 1.2 1993/11/22 10:24:10 mike ; *** empty log message *** ; ; Revision 1.1 1993/09/08 17:29:47 mike ; Initial revision ; ; ; ; VESA in this file must be the same as VESA in tmap.h VESA equ 0 direct_to_video equ 0 %if direct_to_video %if VESA ; for vesa mode WINDOW_LEFT = 0 WINDOW_RIGHT = 300 WINDOW_TOP = 0 WINDOW_BOTTOM = 200 WINDOW_WIDTH = WINDOW_RIGHT - WINDOW_LEFT BYTES_PER_ROW = 300*2 %else ; for non-vesa mode WINDOW_LEFT = 58 WINDOW_RIGHT = 262 WINDOW_TOP = 34 WINDOW_BOTTOM = 167 WINDOW_WIDTH = WINDOW_RIGHT - WINDOW_LEFT BYTES_PER_ROW = 320 ; number of bytes between rows %endif ; for vesa, 15 bit color, 640x480x2 SCREEN_WIDTH = 640 SCREEN_HEIGHT = 480 BYTES_PER_PIXEL = 2 %endif %ifdef __LINUX__ ; It appears that ELF C compilers do not prefix symbols with '_', so here we ; cater for them... %define _gr_fade_table gr_fade_table %define _write_buffer write_buffer %define _window_left window_left %define _window_right window_right %define _window_top window_top %define _window_bottom window_bottom %define _window_width window_width %define _window_height window_height %define _bytes_per_row bytes_per_row %define _y_pointers y_pointers %define _per2_flag per2_flag %define _tmap_flat_cthru_table tmap_flat_cthru_table %define _tmap_flat_color tmap_flat_color %define _tmap_flat_shade_value tmap_flat_shade_value %define _dither_intensity_lighting dither_intensity_lighting %define _Lighting_on Lighting_on %define _Transparency_on Transparency_on %define _fx_u fx_u %define _fx_v fx_v %define _fx_z fx_z %define _fx_l fx_l %define _fx_du_dx fx_du_dx %define _fx_dv_dx fx_dv_dx %define _fx_dz_dx fx_dz_dx %define _fx_dl_dx fx_dl_dx %define _fx_y fx_y %define _fx_xleft fx_xleft %define _fx_xright fx_xright %define _pixptr pixptr %endif extern _gr_fade_table;:byte ;NO_INVERSE_TABLE extrn _gr_inverse_table:byte extern _write_buffer;:dword extern _window_left;:dword extern _window_right;:dword extern _window_top;:dword extern _window_bottom;:dword, extern _window_width;:dword, extern _bytes_per_row;:dword, extern _window_height;:dword extern _y_pointers;:dword ;NO_INVERSE_TABLE _rgb_to_palette equ _gr_inverse_table ;NO_INVERSE_TABLE _pixel_average equ _gr_inverse_table ; should be blend table, but i took it out -john max_window_width equ 320 num_iters equ max_window_width %if num_iters & 1 %assign num_iters num_iters+1 %endif extern _per2_flag;:dword extern _tmap_flat_cthru_table;:dword extern _tmap_flat_color;:byte extern _tmap_flat_shade_value;:byte extern _dither_intensity_lighting;:dword extern _Lighting_on;:dword ; DPH: Selectors are about as portable as a rock. ; extern _pixel_data_selector;:word ; extern _gr_fade_table_selector;:word extern _Transparency_on;:dword extern _fx_u;:dword extern _fx_v;:dword extern _fx_z;:dword extern _fx_l;:dword extern _fx_du_dx;:dword extern _fx_dv_dx;:dword extern _fx_dz_dx;:dword extern _fx_dl_dx;:dword extern _fx_y;:dword extern _fx_xleft;:dword extern _fx_xright;:dword extern _pixptr;:dword dxx-rebirth-0.58.1-d1x/texmap/tmap_lin.asm000077500000000000000000000175471217717257200203760ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmap_lin.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:45:56 $ ; ; Linearly interpolating texture mapper inner loop ; ; $Log: tmap_lin.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:45:56 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:13:53 donut ; Import of d1x 1.37 source. ; ; Revision 1.3 1995/02/20 18:22:57 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.2 1995/02/20 17:09:10 john ; Added code so that you can build the tmapper with no assembly! ; ; Revision 1.1 1994/11/30 12:24:04 mike ; Initial revision ; ; Revision 1.6 1994/11/12 16:39:40 mike ; jae to ja. ; ; Revision 1.5 1994/02/10 21:24:43 matt ; Got rid of debug_on set ; ; Revision 1.4 1994/01/31 15:39:53 mike ; Write additional inner loop for transparency. ; ; Revision 1.3 1994/01/26 11:50:04 john ; Added transparency to linear unlighted texture mapper. ; ; Revision 1.2 1993/11/22 10:24:36 mike ; *** empty log message *** ; ; Revision 1.1 1993/09/08 17:29:50 mike ; Initial revision ; ; ; [BITS 32] global _asm_tmap_scanline_lin global asm_tmap_scanline_lin [SECTION .data] %include "tmap_inc.asm" _loop_count dd 0 [SECTION .text] ; -------------------------------------------------------------------------------------------------- ; Enter: ; _xleft fixed point left x coordinate ; _xright fixed point right x coordinate ; _y fixed point y coordinate ; _pixptr address of source pixel map ; _u fixed point initial u coordinate ; _v fixed point initial v coordinate ; _du_dx fixed point du/dx ; _dv_dx fixed point dv/dx ; for (x = (int) xleft; x <= (int) xright; x++) { ; _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63)); ; _setpixel(x,y); ; ; u += du_dx; ; v += dv_dx; ; z += dz_dx; ; } align 4 _asm_tmap_scanline_lin: asm_tmap_scanline_lin: pusha ; Setup for loop: _loop_count iterations = (int) xright - (int) xleft ; esi source pixel pointer = pixptr ; edi initial row pointer = y*320+x ; set esi = pointer to start of texture map data mov esi,[_pixptr] ; set edi = address of first pixel to modify mov edi,[_fx_y] cmp edi,[_window_bottom] ja near _none_to_do imul edi,[_bytes_per_row] mov eax,[_fx_xleft] test eax, eax jns eax_ok sub eax,eax eax_ok: add edi,eax add edi,[_write_buffer] ; set _loop_count = # of iterations mov eax,[_fx_xright] cmp eax,[_window_right] jb eax_ok1 mov eax,[_window_right] eax_ok1: cmp eax,[_window_left] ja eax_ok2 mov eax,[_window_left] eax_ok2: mov ebx,[_fx_xleft] sub eax,ebx js near _none_to_do cmp eax,[_window_width] jbe _ok_to_do mov eax,[_window_width] _ok_to_do: mov [_loop_count],eax ; edi destination pixel pointer mov ebx,[_fx_u] mov ecx,[_fx_du_dx] mov edx,[_fx_dv_dx] mov ebp,[_fx_v] shl ebx,10 shl ebp,10 shl edx,10 shl ecx,10 ; eax work ; ebx u ; ecx du_dx ; edx dv_dx ; ebp v ; esi read address ; edi write address test dword [_Transparency_on],-1 jne near transparent_texture %define _size (_end1 - _start1)/num_iters mov eax,num_iters-1 sub eax,[_loop_count] jns j_eax_ok1 inc eax ; sort of a hack, but we can get -1 here and want to be graceful jns j_eax_ok1 ; if we jump, we had -1, which is kind of ok, if not, we int 3 int 3 ; oops, going to jump behind _start1, very bad... sub eax,eax ; ok to continue j_eax_ok1: imul eax,eax,_size add eax,_start1 jmp eax align 4 _start1: ; "OPTIMIZATIONS" maybe not worth making ; Getting rid of the esi from the mov al,[esi+eax] instruction. ; This would require moving into eax at the top of the loop, rather than doing the sub eax,eax. ; You would have to align your bitmaps so that the two shlds would create the proper base address. ; In other words, your bitmap data would have to begin at 4096x (for 64x64 bitmaps). ; I did timings without converting the sub to a mov eax,esi and setting esi to the proper value. ; There was a speedup of about 1% to 1.5% without converting the sub to a mov. ; Getting rid of the edi by doing a mov nnnn[edi],al instead of mov [edi],al. ; The problem with this is you would have a dword offset for nnnn. My timings indicate it is slower. (I think.) ; Combining u,v and du,dv into single longwords. ; The problem with this is you then must do a 16 bit operation to extract them, and you don't have enough ; instructions to separate a destination operand from being used by the next instruction. It shaves out one ; register instruction (an add reg,reg), but adds a 16 bit operation, and the setup is more complicated. ; usage: ; eax work ; ebx u coordinate ; ecx delta u ; edx delta v ; ebp v coordinate ; esi pointer to source bitmap ; edi write address %rep num_iters mov eax,ebp ; clear for add ebp,edx ; update v coordinate shr eax,26 ; shift in v coordinate shld eax,ebx,6 ; shift in u coordinate while shifting up v coordinate add ebx,ecx ; update u coordinate mov al,[esi+eax] ; get pixel from source bitmap mov [edi],al inc edi ; XPARENT ADDED BY JOHN ; inner loop if bitmaps are 256x256 ; your register usage is bogus, and you must clear ecx ; fix your setup ; this is only about 10% faster in the inner loop ; this method would adapt to writing two pixels at a time better than ; the 64x64 method because you wouldn't run out of registers ; Note that this method assumes that both dv_dx and du_dx are in edx. ; edx = vi|vf|ui|uf ; where each field is 8 bits, vi = integer v coordinate, vf = fractional v coordinate, etc. ;** add ebx,edx ;** mov cl,bh ;** shld cx,bx,8 ;** mov al,[esi+ecx] ;** mov [edi],al ;** inc edi %endrep _end1: _none_to_do: popa ret ; ---------------------------------------------------------------------------------------- ; if texture map has transparency, use this code. transparent_texture: test dword [_loop_count],-1 je _t_none_to_do loop_transparent: mov eax,ebp ; clear for add ebp,edx ; update v coordinate shr eax,26 ; shift in v coordinate shld eax,ebx,6 ; shift in u coordinate while shifting up v coordinate add ebx,ecx ; update u coordinate mov al,[esi+eax] ; get pixel from source bitmap cmp al,255 je transp mov [edi],al transp: inc edi ; XPARENT ADDED BY JOHN dec dword [_loop_count] jne loop_transparent _t_none_to_do: popa ret ; This is the inner loop to write two pixels at a time ; This is about 2.5% faster overall (on Mike's 66 MHz 80486 DX2, VLB) ; You must write code to even align edi and do half as many iterations, and write ; the beginning and ending extra pixels, if necessary. ; sub eax,eax ; clear for ; shld eax,ebp,6 ; shift in v coordinate ; add ebp,_fx_dv_dx ; update v coordinate ; shld eax,ebx,6 ; shift in u coordinate while shifting up v coordinate ; add ebx,ecx ; update u coordinate ; mov dl,[esi+eax] ; get pixel from source bitmap ; ; sub eax,eax ; clear for ; shld eax,ebp,6 ; shift in v coordinate ; add ebp,_fx_dv_dx ; update v coordinate ; shld eax,ebx,6 ; shift in u coordinate while shifting up v coordinate ; add ebx,ecx ; update u coordinate ; mov dh,[esi+eax] ; get pixel from source bitmap ; ; mov [edi],dx ; add edi,2 dxx-rebirth-0.58.1-d1x/texmap/tmap_ll.asm000077500000000000000000000307161217717257200202140ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmap_ll.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:46:04 $ ; ; Linear, lighted texture mapper inner loop. ; ; $Log: tmap_ll.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:46:04 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:13:55 donut ; Import of d1x 1.37 source. ; ; Revision 1.10 1995/02/20 18:22:54 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.9 1995/02/20 17:09:06 john ; Added code so that you can build the tmapper with no assembly! ; ; Revision 1.8 1994/11/19 23:52:56 mike ; rip out big unrolled loop to save 25K....remember when we cared more about speed? ; ; Revision 1.7 1994/11/12 16:39:41 mike ; jae to ja. ; ; Revision 1.6 1994/03/14 15:45:08 mike ; streamline code. ; ; Revision 1.5 1994/01/24 13:13:12 mike ; dithering. ; ; Revision 1.4 1994/01/14 14:02:47 mike ; *** empty log message *** ; ; Revision 1.3 1993/12/17 20:00:16 mike ; Change default setting of dither_intensity_lighting from 1 to 0 ; ; Revision 1.2 1993/11/22 10:24:50 mike ; *** empty log message *** ; ; Revision 1.1 1993/09/08 17:29:52 mike ; Initial revision ; ; ; [BITS 32] global _asm_tmap_scanline_lin_lighted global asm_tmap_scanline_lin_lighted [SECTION .data] %include "tmap_inc.asm" ALLOW_DITHERING equ 1 _fx_dl_dx1 dd 0 _fx_dl_dx2 dd 0 _loop_count dd 0 [SECTION .text] ; -------------------------------------------------------------------------------------------------- ; Enter: ; _xleft fixed point left x coordinate ; _xright fixed point right x coordinate ; _y fixed point y coordinate ; _pixptr address of source pixel map ; _u fixed point initial u coordinate ; _v fixed point initial v coordinate ; _du_dx fixed point du/dx ; _dv_dx fixed point dv/dx ; for (x = (int) xleft; x <= (int) xright; x++) { ; _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63)); ; _setpixel(x,y); ; ; u += du_dx; ; v += dv_dx; ; z += dz_dx; ; } align 4 _asm_tmap_scanline_lin_lighted: asm_tmap_scanline_lin_lighted: ; push es ; DPH: No selectors in windows :-( ; push fs pusha ; mov es,[_pixel_data_selector] ; selector[0*2] ; DPH: No... :-) ; mov fs,[_gr_fade_table_selector] ; selector[1*2] ; fs = bmd_fade_table ; Setup for loop: _loop_count iterations = (int) xright - (int) xleft ; esi source pixel pointer = pixptr ; edi initial row pointer = y*320+x ; set esi = pointer to start of texture map data mov esi,[_pixptr] ; set edi = address of first pixel to modify mov edi,[_fx_y] ; this is actually an int cmp edi,[_window_bottom] ja near all_done imul edi,[_bytes_per_row] mov ebx,[_fx_xleft] test ebx,ebx jns ebx_ok sub ebx,ebx ebx_ok: add edi,ebx add edi,[_write_buffer] ; set _loop_count = # of iterations mov eax,[_fx_xright] cmp eax,[_window_right] jl eax_ok1 mov eax,[_window_right] eax_ok1: cmp eax,[_window_left] jg eax_ok2 mov eax,[_window_left] eax_ok2: sub eax,ebx js near all_done cmp eax,[_window_width] jbe _ok_to_do mov eax,[_window_width] _ok_to_do: mov [_loop_count],eax ; edi destination pixel pointer mov ecx,_gr_fade_table ;originally offset _lighting_tables mov eax,[_fx_u] ; get 32 bit u coordinate shr eax,6 ; get 6:10 int:frac u coordinate into low word mov ebp,[_fx_v] ; get 32 bit v coordinate shl ebp,10 ; put 6:10 int:frac into high word mov bp,ax ; put u coordinate in low word mov eax,[_fx_du_dx] ; get 32 bit delta u shr eax,6 ; get 6:10 int:frac delta u into low word mov edx,[_fx_dv_dx] ; get 32 bit delta v shl edx,10 ; put 6:10 int:frac into high word mov dx,ax ; put delta u in low word sar dword [_fx_dl_dx],8 jns dl_dx_ok inc dword [_fx_dl_dx] ; round towards 0 for negative deltas dl_dx_ok: %if ALLOW_DITHERING ; do dithering, use lighting values which are .5 less than and .5 more than actual value mov ebx,80h ; assume dithering on test dword [_dither_intensity_lighting],-1 jne do_dither sub ebx,ebx ; no dithering do_dither: mov eax,[_fx_dl_dx] add eax,ebx ; add 1/2 mov [_fx_dl_dx1],eax sub eax,ebx sub eax,ebx mov [_fx_dl_dx2],eax mov ebx,[_fx_xleft] xor ebx,[_fx_y] and ebx,1 jne dith_1 xchg eax,[_fx_dl_dx1] dith_1: mov [_fx_dl_dx2],eax %endif mov ebx,[_fx_l] ; lighting values are passed in fixed point, but need to be in 8 bit integer, 8 bit fraction so we can easily ; get the integer by reading %bh sar ebx,8 test dword [_Transparency_on],-1 jne do_transparency_ll ;; esi, ecx should be free loop_test equ 1 ; set to 1 to run as loop for better profiling %if loop_test mov esi,[_fx_dl_dx] mov ecx,[_loop_count] inc ecx shr ecx,1 je one_more_pix pushf align 4 loop1: mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv add eax,[_pixptr] ; DPH: No selectors in windows movzx eax,byte [eax] ; get pixel from source bitmap mov ah,bh ; get lighting table add ebx,esi ; _fx_dl_dx ; update lighting value mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... inc edi ; ...and advance ; --- --- mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv add eax,[_pixptr] ; DPH: movzx eax,byte [eax] ; get pixel from source bitmap mov ah,bh ; get lighting table add ebx,esi ; _fx_dl_dx ; update lighting value mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... inc edi ; ...and advance dec ecx ; _loop_count jne loop1 popf jnc all_done one_more_pix: mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add eax,[_pixptr] ; DPH: movzx eax,byte [eax] ; get pixel from source bitmap mov ah,bh ; get lighting table mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... all_done: popa ; pop fs ; pop es ret %else ; usage: ; eax work ; ebx lighting value ; ecx _lighting_tables ; edx du, dv 6:10:6:10 ; ebp u, v coordinates 6:10:6:10 ; esi pointer to source bitmap ; edi write address ;_size = (_end1 - _start1)/num_iters ; note: if eax is odd, you will not be writing the last pixel, you must clean up at the end %if ALLOW_DITHERING mov eax,[_loop_count] shr eax,1 neg eax add eax,num_iters %else mov eax,num_iters sub eax,[_loop_count] %endif imul eax,eax,(_end1 - _start1)/num_iters add eax,_start1 ;originally offset _start1 jmp eax align 4 _start1: ; usage: ; eax work ; ebx lighting value ; ecx _lighting_tables ; edx du, dv 6:10:6:10 ; ebp u, v coordinates 6:10:6:10 ; esi pointer to source bitmap ; edi write address ; do all but the last pixel in the unwound loop, last pixel done separately because less work is needed %rep num_iters %if 1 ;**; inner loop if lighting value is constant ;**; can be optimized if source bitmap pixels are stored as words, then the mov ah,bh is not necessary ;** mov eax,ebp ; get u, v ;** shr eax,26 ; shift out all but int(v) ;** shld ax,bp,6 ; shift in u, shifting up v ;** ;** add ebp,edx ; u += du, v += dv ;** ;** mov al,[esi+eax] ; get pixel from source bitmap ;** mov ah,bh ; get lighting table ;** mov al,[ecx+eax] ; xlat pixel through lighting tables ;** mov [edi],al ; write pixel... ;** inc edi ; ...and advance %if ALLOW_DITHERING ; dithering ; loop contains two iterations which must be the same length mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv mov al,[esi+eax] ; get pixel from source bitmap mov ah,bh ; get lighting table add ebx,[_fx_dl_dx1] ; update lighting value mov al,[ecx+eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... inc edi ; ...and advance ; second iteration mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv mov al,[esi+eax] ; get pixel from source bitmap mov ah,bh ; get lighting table add ebx,[_fx_dl_dx2] ; update lighting value mov al,[ecx+eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... inc edi ; ...and advance %else mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv mov al,[esi+eax] ; get pixel from source bitmap mov ah,bh ; get lighting table add ebx,[_fx_dl_dx] ; update lighting value mov al,[ecx+eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... inc edi ; ...and advance %endif %else ;obsolete: ; version which assumes segment overrides are in place (which they are obviously not) ;obsolete: mov eax,ebp ; get u, v ;obsolete: shr eax,26 ; shift out all but int(v) ;obsolete: shld ax,bp,6 ; shift in u, shifting up v ;obsolete: ;obsolete: add ebp,edx ; u += du, v += dv ;obsolete: ;obsolete: mov al,[eax] ; get pixel from source bitmap ;obsolete: mov ah,bh ; get lighting table ;obsolete: add ebx,esi ; update lighting value ;obsolete: mov al,[eax] ; xlat pixel through lighting tables ;obsolete: mov [edi],al ; write pixel... ;obsolete: inc edi ; ...and advance %endif %endrep _end1: ; now do the leftover pixel mov eax,ebp shr eax,26 ; shift in v coordinate shld ax,bp,6 ; shift in u coordinate while shifting up v coordinate mov al,[esi+eax] ; get pixel from source bitmap mov ah,bh ; get lighting table or ah,ah jns ok1 sub ah,ah ok1: mov al,[_gr_fade_table+eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... _none_to_do: popa ; pop fs ; pop es ret %endif ; -- Code to get rgb 5 bits integer, 5 bits fraction value into 5 bits integer (for each gun) ; suitable for inverse color lookup ;**__test: ;** int 3 ;**; rrrrrfffffrrrrrfffffxxbbbbbfffff ;** mov eax,11111001001010101110101101110111b ;** and eax,11111000001111100000001111100000b ;** shld ebx,eax,15 ;** or bx,ax ;; esi, ecx should be free do_transparency_ll: mov esi,[_fx_dl_dx] mov ecx,[_loop_count] inc ecx shr ecx,1 je one_more_pix2 pushf align 4 loop1a: mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv add eax,[_pixptr] ; DPH: movzx eax,byte [eax] ; get pixel from source bitmap cmp al,255 je skip1a mov ah,bh ; get lighting table add ebx,esi ; _fx_dl_dx ; update lighting value mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... skip1a: inc edi ; ...and advance ; --- --- mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add ebp,edx ; u += du, v += dv add eax,[_pixptr] ; DPH: movzx eax,byte [eax] ; get pixel from source bitmap cmp al,255 je skip2a mov ah,bh ; get lighting table add ebx,esi ; _fx_dl_dx ; update lighting value mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... skip2a: inc edi ; ...and advance dec ecx ; _loop_count jne loop1a popf jnc all_done_1 one_more_pix2: mov eax,ebp ; get u, v shr eax,26 ; shift out all but int(v) shld ax,bp,6 ; shift in u, shifting up v add eax,[_pixptr] ; DPH: movzx eax,byte [eax] ; get pixel from source bitmap cmp al,255 je skip3a mov ah,bh ; get lighting table mov al,[_gr_fade_table + eax] ; xlat pixel through lighting tables mov [edi],al ; write pixel... skip3a: all_done_1: popa ; pop fs ; DPH: ; pop es ret dxx-rebirth-0.58.1-d1x/texmap/tmap_per.asm000077500000000000000000000771651217717257200204040ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmap_per.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:46:03 $ ; ; Perspective texture mapper inner loop. ; ; $Log: tmap_per.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:46:03 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:14:01 donut ; Import of d1x 1.37 source. ; ; Revision 1.26 1995/02/20 18:22:55 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.25 1995/02/20 17:09:08 john ; Added code so that you can build the tmapper with no assembly! ; ; Revision 1.24 1995/01/10 09:32:07 mike ; mostly fix garbage at end of scanline, but slow down by 1-4%. ; ; Revision 1.23 1994/12/02 23:29:57 mike ; optimizations. ; ; Revision 1.22 1994/11/30 00:57:00 mike ; optimization. ; ; Revision 1.21 1994/11/21 13:57:42 mike ; fix right side shear bug ; ; Revision 1.20 1994/11/12 16:41:09 mike ; jae -> ja. ; ; Revision 1.19 1994/10/27 19:40:00 john ; Made lighting table lookup be _gr_fade_table[eax] instead ; of fs:[eax], which gets rig of a segment override that ; supposedly costs 1 clock on a 486. Mainly, I wanted to verify ; that the only reason we need selectors is for the source texture ; data . ; ; Revision 1.18 1994/05/03 11:08:32 mike ; Trap divide overflows. ; ; Revision 1.17 1994/04/21 15:03:41 mike ; make faster. ; ; Revision 1.16 1994/04/08 16:46:57 john ; Made 32 fade levels. Hacked. ; ; Revision 1.15 1994/03/31 08:35:18 mike ; Fix quantized-by-4 bug in inner loop. ; ; Revision 1.14 1994/03/14 17:41:14 mike ; Fix bug in unlighted version. ; ; Revision 1.13 1994/03/14 15:45:14 mike ; streamline code. ; ; Revision 1.12 1994/01/14 14:01:58 mike ; *** empty log message *** ; ; Revision 1.11 1993/12/18 14:43:44 john ; Messed around with doing 1/z, the u*(1/z) and v*(1/z) ; (Went from 23 fps to 21 fps... not good! ) ; ; Revision 1.10 1993/12/17 16:14:17 john ; Split lighted/nonlighted, so there is no cmp lighting ; in the inner loop. ; ; Revision 1.9 1993/12/17 12:34:29 john ; Made leftover bytes use linear approx instead of correct... ; should save about 8 divides per scanline on average. ; Also, took out anti-aliasing code and rearranged to ; order of some instructions to help on 486 pipelining. ; (The anti-aliasing code did *not* look good, so I ; figure there was no reason to keep it in. ) ; ; Revision 1.8 1993/12/16 18:37:52 mike ; Align some stuff on 4 byte boundaries. ; ; Revision 1.7 1993/11/30 08:44:18 john ; Made selector set check for < 64*64 bitmaps. ; ; Revision 1.6 1993/11/23 17:25:26 john ; Added safety "and eax, 0fffh" in lighting lookup. ; ; Revision 1.5 1993/11/23 15:08:52 mike ; Fixed lighting bug. ; ; Revision 1.4 1993/11/23 14:38:50 john ; optimized NORMAL code by switching EBX and ESI, so BH can be used in ; the lighting process. ; ; Revision 1.3 1993/11/23 14:30:53 john ; Made the perspective tmapper do 1/8 divides; added lighting. ; ; Revision 1.2 1993/11/22 10:24:59 mike ; *** empty log message *** ; ; Revision 1.1 1993/09/08 17:29:53 mike ; Initial revision ; ; ; [BITS 32] global _asm_tmap_scanline_per global asm_tmap_scanline_per %include "tmap_inc.asm" [SECTION .data] align 4 ;extern _per2_flag;:dword %ifdef __LINUX__ ; Cater for linux ELF compilers... global x %define _loop_count loop_count %define _new_end new_end %define _scan_doubling_flag scan_doubling_flag %define _linear_if_far_flag linear_if_far_flag %endif global _x global _loop_count global _new_end global _scan_doubling_flag global _linear_if_far_flag ; global _max_ecx ; global _min_ecx mem_edx dd 0 x: _x dd 0 _loop_count dd 0 ; _max_ecx dd 0 ; _min_ecx dd 55555555h _new_end dd 1 ; if set, use new, but slower, way of finishing off extra pixels on scanline, 01/10/95 --MK _scan_doubling_flag dd 0 _linear_if_far_flag dd 0 ;---------- local variables align 4 req_base dd 0 req_size dd 0 U0 dd 0 U1 dd 0 V0 dd 0 V1 dd 0 num_left_over dd 0 DU1 dd 0 DV1 dd 0 DZ1 dd 0 [SECTION .text] ; -------------------------------------------------------------------------------------------------- ; Enter: ; _xleft fixed point left x coordinate ; _xright fixed point right x coordinate ; _y fixed point y coordinate ; _pixptr address of source pixel map ; _u fixed point initial u coordinate ; _v fixed point initial v coordinate ; _z fixed point initial z coordinate ; _du_dx fixed point du/dx ; _dv_dx fixed point dv/dx ; _dz_dx fixed point dz/dx ; for (x = (int) xleft; x <= (int) xright; x++) { ; _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63)); ; _setpixel(x,y); ; ; u += du_dx; ; v += dv_dx; ; z += dz_dx; ; } align 16 _asm_tmap_scanline_per: asm_tmap_scanline_per: ; push es pusha ;---------------------------- setup for loop --------------------------------- ; Setup for loop: _loop_count iterations = (int) xright - (int) xleft ; esi source pixel pointer = pixptr ; edi initial row pointer = y*320+x ; NOTE: fx_xright and fx_xleft changed from fix to int by mk on 12/01/94. ; set esi = pointer to start of texture map data ; set edi = address of first pixel to modify mov edi,[_fx_y] ; mov es,[_pixel_data_selector] ; selector[0*2] mov edi,[_y_pointers+edi*4] mov ebx,[_fx_xleft] test ebx, ebx jns ebx_ok xor ebx, ebx ebx_ok: add edi,[_write_buffer] add edi,ebx ; set _loop_count = # of iterations mov eax,[_fx_xright] sub eax,ebx js near _none_to_do mov [_loop_count],eax ; lighting values are passed in fixed point, but need to be in 8 bit integer, 8 bit fraction so we can easily ; get the integer by reading %bh sar dword [_fx_l], 8 sar dword [_fx_dl_dx],8 jns dl_dx_ok inc dword [_fx_dl_dx] ; round towards 0 for negative deltas dl_dx_ok: ; set initial values mov ebx,[_fx_u] mov ebp,[_fx_v] mov ecx,[_fx_z] test dword [_per2_flag],-1 je tmap_loop test dword [_Lighting_on], -1 je near _tmap_loop_fast_nolight jmp _tmap_loop_fast ;tmap_loop_fast_nolight_jumper: ; jmp tmap_loop_fast_nolight ;================ PERSPECTIVE TEXTURE MAP INNER LOOPS ======================== ; ; Usage in loop: eax division, pixel value ; ebx u ; ecx z ; edx division ; ebp v ; esi source pixel pointer ; edi destination pixel pointer ;-------------------- NORMAL PERSPECTIVE TEXTURE MAP LOOP ----------------- tmap_loop: mov esi, ebx ; esi becomes u coordinate align 4 tmap_loop0: ; compute v coordinate mov eax, ebp ; get v mov edx, eax sar edx, 31 idiv ecx ; eax = (v/z) and eax,3fh ; mask with height-1 mov ebx,eax ; compute u coordinate mov eax, esi ; get u mov edx, eax sar edx, 31 idiv ecx ; eax = (u/z) shl eax,26 shld ebx,eax,6 ; esi = v*64+u ; read 1 pixel add ebx, [_pixptr] xor eax, eax test dword [_Lighting_on], -1 mov al, [ebx] ; get pixel from source bitmap je NoLight1 ; LIGHTING CODE mov ebx, [_fx_l] ; get temp copy of lighting value mov ah, bh ; get lighting level add ebx, [_fx_dl_dx] ; update lighting value mov al, [_gr_fade_table+eax] ; xlat pixel thru lighting tables mov [_fx_l], ebx ; save temp copy of lighting value ; transparency check NoLight1: cmp al,255 je skip1 mov [edi],al skip1: inc edi ; update deltas add ebp,[_fx_dv_dx] add esi,[_fx_du_dx] add ecx,[_fx_dz_dx] je _div_0_abort ; would be dividing by 0, so abort dec dword [_loop_count] jns tmap_loop0 _none_to_do: popa ; pop es ret ; We detected a z=0 condition, which seems pretty bogus, don't you think? ; So, we abort, but maybe we want to know about it. _div_0_abort: jmp _none_to_do ;-------------------------- PER/4 TMAPPER ---------------- ; ; x = x1 ; U0 = u/w; V0 = v/w; ; while ( 1 ) ; u += du_dx*4; v+= dv_dx*4 ; U1 = u/w; V1 = v/w; ; DUDX = (U1-U0)/4; DVDX = (V1-V0)/4; ; ; ; Pixel 0 ; pixels = texmap[V0*64+U0]; ; U0 += DUDX; V0 += DVDX ; ; Pixel 1 ; pixels = (pixels<<8)+texmap[V0*64+U0]; ; U0 += DUDX; V0 += DVDX ; ; Pixel 2 ; pixels = (pixels<<8)+texmap[V0*64+U0]; ; U0 += DUDX; V0 += DVDX ; ; Pixel 3 ; pixels = (pixels<<8)+texmap[V0*64+U0]; ; ; screen[x] = pixel ; x += 4; ; U0 = U1; V0 = V1 NBITS equ 4 ; 2^NBITS pixels plotted per divide ZSHIFT equ 4 ; precision used in PDIV macro ;PDIV MACRO ; Returns EAX/ECX in 16.16 format in EAX. Trashes EDX ; sig bits 6.3 ; mov edx,eax ; shl eax,ZSHIFT ; sar edx,32-ZSHIFT ; idiv ecx ; eax = (v/z) ; shl eax, 16-ZSHIFT ;ENDM global _tmap_loop_fast ; -------------------------------------- Start of Getting Dword Aligned ---------------------------------------------- ; ebx fx_u _tmap_loop_fast: mov esi,ebx align 4 NotDwordAligned1: test edi, 11b jz DwordAligned1 ; compute v coordinate mov eax, ebp ; get v mov edx, eax sar edx, 31 idiv ecx ; eax = (v/z) and eax,3fh ; mask with height-1 mov ebx,eax ; compute u coordinate mov eax, esi ; get u mov edx, eax sar edx, 31 idiv ecx ; eax = (u/z) shl eax,26 shld ebx,eax,6 ; esi = v*64+u ; read 1 pixel add ebx,[_pixptr] xor eax, eax mov al, [ebx] ; get pixel from source bitmap ; lighting code mov ebx, [_fx_l] ; get temp copy of lighting value mov ah, bh ; get lighting level add ebx, [_fx_dl_dx] ; update lighting value mov [_fx_l], ebx ; save temp copy of lighting value ; transparency check cmp al,255 je skip2 ; this pixel is transparent, so don't write it (or light it) mov al, [_gr_fade_table+eax] ; xlat pixel thru lighting tables ; write 1 pixel mov [edi],al skip2: inc edi ; update deltas add ebp,[_fx_dv_dx] add esi,[_fx_du_dx] add ecx,[_fx_dz_dx] je _div_0_abort ; would be dividing by 0, so abort dec dword [_loop_count] jns NotDwordAligned1 jmp _none_to_do ; -------------------------------------- End of Getting Dword Aligned ---------------------------------------------- DwordAligned1: mov eax, [_loop_count] mov ebx, esi ; get fx_u [pentium pipelining] inc eax mov esi, eax and esi, (1 << NBITS) - 1 sar eax, NBITS mov [num_left_over], esi je near tmap_loop ; there are no 2^NBITS chunks, do divide/pixel for whole scanline mov [_loop_count], eax ; _loop_count = pixels / NPIXS ; compute initial v coordinate mov eax,ebp ; get v mov edx,ebp shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov [V0], eax ; compute initial u coordinate mov eax,ebx ; get u mov edx,ebx shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov [U0], eax ; Set deltas to NPIXS pixel increments mov eax, [_fx_du_dx] shl eax, NBITS mov [DU1], eax mov eax, [_fx_dv_dx] shl eax, NBITS mov [DV1], eax mov eax, [_fx_dz_dx] shl eax, NBITS mov [DZ1], eax align 4 TopOfLoop4: add ebx, [DU1] add ebp, [DV1] add ecx, [DZ1] je near _div_0_abort ; would be dividing by 0, so abort ; Done with ebx, ebp, ecx until next iteration push ebx push ecx push ebp push edi ; Find fixed U1 mov eax, ebx mov edx,ebx shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebx, eax ; ebx = U1 until pop's ; Find fixed V1 mov eax, ebp mov edx, ebp shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) mov ecx, [U0] ; ecx = U0 until pop's mov edi, [V0] ; edi = V0 until pop's shl eax, 16-ZSHIFT mov ebp, eax ; ebp = V1 until pop's ; Make ESI = V0:U0 in 6:10,6:10 format mov eax, ecx shr eax, 6 mov esi, edi shl esi, 10 mov si, ax ; Make EDX = DV:DU in 6:10,6:10 format mov eax, ebx sub eax, ecx sar eax, NBITS+6 mov edx, ebp sub edx, edi shl edx, 10-NBITS ; EDX = V1-V0/ 4 in 6:10 int:frac mov dx, ax ; put delta u in low word ; Save the U1 and V1 so we don't have to divide on the next iteration mov [U0], ebx mov [V0], ebp pop edi ; Restore EDI before using it ; LIGHTING CODE mov ebx, [_fx_l] mov ebp, [_fx_dl_dx] test dword [_Transparency_on],-1 je near no_trans1 %macro repproc1 0 mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add esi, edx ; inc u,v add eax, [_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap cmp al,255 je %%skipa1 mov ah, bh ; form lighting table lookup value add ebx, ebp ; update lighting value mov al, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer mov [edi],al %%skipa1: inc edi ; Do odd pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add esi, edx ; inc u,v add eax,[_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap cmp al,255 je %%skipa2 mov ah, bh ; form lighting table lookup value add ebx, ebp ; update lighting value mov al, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer mov [edi],al %%skipa2: inc edi %endmacro %rep (2 << (NBITS-2)) ; local skip3,no_trans1 ; local skipa1,skipa2 repproc1 %endrep jmp cont1 ; ------------------------------------------------------- no_trans1: %macro repproc2 0 mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add esi, edx ; inc u,v add eax,[_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap mov ah, bh ; form lighting table lookup value add ebx, ebp ; update lighting value mov cl, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer ; Do odd pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add esi, edx ; inc u,v add eax,[_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap mov ah, bh ; form lighting table lookup value add ebx, ebp ; update lighting value mov ch, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer ; ----- This is about 1% faster than the above, and could probably be optimized more. ; ----- Problem is, it gets the u,v coordinates backwards. What you would need to do ; ----- is switch the packing of the u,v coordinates above (about 95 lines up). ;----------; mov eax, esi ;----------; shr ax, 10 ;----------; rol eax, 6 ;----------; mov dx, ax ;----------; add esi, mem_edx ;----------; mov dl, es:[edx] ;----------; mov dh, bh ;----------; add ebx, ebp ;----------; mov cl, _gr_fade_table[edx] ;----------; ;----------; mov eax, esi ;----------; shr ax, 10 ;----------; rol eax, 6 ;----------; mov dx, ax ;----------; add esi, mem_edx ;----------; mov dl, es:[edx] ;----------; mov dh, bh ;----------; add ebx, ebp ;----------; mov ch, _gr_fade_table[edx] ror ecx, 16 ; move to next double dest pixel position %endmacro %rep (1 << (NBITS-2)) repproc2 repproc2 mov [edi],ecx ; Draw 4 pixels to display add edi,4 %endrep ;; pop edx cont1: ; ------------------------------------------------------- ; LIGHTING CODE mov [_fx_l], ebx pop ebp pop ecx pop ebx dec dword [_loop_count] jnz near TopOfLoop4 EndOfLoop4: test dword [num_left_over], -1 je near _none_to_do ; ----------------------------------------- Start of LeftOver Pixels ------------------------------------------ DoEndPixels: push ecx mov eax, ecx lea eax, [eax*2+eax] add ecx, [DZ1] js notokhere shl ecx,2 cmp eax, ecx pop ecx jl okhere jmp bah_bah notokhere: pop ecx bah_bah: test dword [_new_end],-1 jne near NewDoEndPixels okhere: add ebx, [DU1] add ebp, [DV1] add ecx, [DZ1] je near _div_0_abort jns dep_cont ; z went negative. ; this can happen because we added DZ1 to the current z, but dz1 represents dz for perhaps 16 pixels ; though we might only plot one more pixel. mov cl, 1 dep_loop: mov eax, [DU1] sar eax, cl sub ebx, eax mov eax, [DV1] sar eax, cl sub ebp, eax mov eax, [DZ1] sar eax, cl sub ecx, eax je near _div_0_abort jns dep_cont inc cl cmp cl, NBITS jne dep_loop dep_cont: push edi ; use edi as a temporary variable cmp ecx,1 << (ZSHIFT+1) jg ecx_ok mov ecx, 1 << (ZSHIFT+1) ecx_ok: ; Find fixed U1 mov eax, ebx ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebx, eax ; ebx = U1 until pop's ; Find fixed V1 mov eax, ebp ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebp, eax ; ebp = V1 until pop's mov ecx, [U0] ; ecx = U0 until pop's mov edi, [V0] ; edi = V0 until pop's ; Make ESI = V0:U0 in 6:10,6:10 format mov eax, ecx shr eax, 6 mov esi, edi shl esi, 10 mov si, ax ; Make EDX = DV:DU in 6:10,6:10 format mov eax, ebx sub eax, ecx sar eax, NBITS+6 mov edx, ebp sub edx, edi shl edx, 10-NBITS ; EDX = V1-V0/ 4 in 6:10 int:frac mov dx, ax ; put delta u in low word pop edi ; Restore EDI before using it mov ecx, [num_left_over] ; LIGHTING CODE mov ebx, [_fx_l] mov ebp, [_fx_dl_dx] ITERATION equ 0 %macro repproc3 0 ; Do even pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap add esi, edx ; inc u,v mov ah, bh ; form lighting table lookup value add ebx, ebp ; update lighting value cmp al,255 je %%skip4 mov al, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer mov [edi+ITERATION], al ; write pixel %%skip4: dec ecx jz near _none_to_do ; Do odd pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] movzx eax, byte [eax] ; get pixel from source bitmap add esi, edx ; inc u,v mov ah, bh ; form lighting table lookup value add ebx, [_fx_dl_dx] ; update lighting value cmp al,255 je %%skip5 mov al, [_gr_fade_table+eax] ; xlat thru lighting table into dest buffer mov [edi+ITERATION+1], al ; write pixel %%skip5: dec ecx jz near _none_to_do %endmacro %rep (1 << (NBITS-1)) ;local skip4, skip5 repproc3 %assign ITERATION ITERATION + 2 %endrep ; Should never get here!!!! int 3 jmp _none_to_do ; ----------------------------------------- End of LeftOver Pixels ------------------------------------------ ; --BUGGY NEW--NewDoEndPixels: ; --BUGGY NEW-- mov eax, num_left_over ; --BUGGY NEW-- and num_left_over, 3 ; --BUGGY NEW-- shr eax, 2 ; --BUGGY NEW-- je NDEP_1 ; --BUGGY NEW-- mov _loop_count, eax ; --BUGGY NEW-- ; --BUGGY NEW--; do 4 pixels per hunk, not 16, so div deltas by 4 (16/4=4) ; --BUGGY NEW-- shr DU1,2 ; --BUGGY NEW-- shr DV1,2 ; --BUGGY NEW-- shr DZ1,2 ; --BUGGY NEW-- ; --BUGGY NEW--NDEP_TopOfLoop4: ; --BUGGY NEW-- add ebx, DU1 ; --BUGGY NEW-- add ebp, DV1 ; --BUGGY NEW-- add ecx, DZ1 ; --BUGGY NEW-- je _div_0_abort ; would be dividing by 0, so abort ; --BUGGY NEW-- ; --BUGGY NEW--; Done with ebx, ebp, ecx until next iteration ; --BUGGY NEW-- push ebx ; --BUGGY NEW-- push ecx ; --BUGGY NEW-- push ebp ; --BUGGY NEW-- push edi ; --BUGGY NEW-- ; --BUGGY NEW--; Find fixed U1 ; --BUGGY NEW-- mov eax, ebx ; --BUGGY NEW-- mov edx,ebx ; --BUGGY NEW-- shl eax,(ZSHIFT-2) ; --BUGGY NEW-- sar edx,32-(ZSHIFT-2) ; --BUGGY NEW-- idiv ecx ; eax = (v/z) ; --BUGGY NEW-- shl eax, 16-(ZSHIFT-2) ; --BUGGY NEW-- mov ebx, eax ; ebx = U1 until pop's ; --BUGGY NEW-- ; --BUGGY NEW--; Find fixed V1 ; --BUGGY NEW-- mov eax, ebp ; --BUGGY NEW-- mov edx, ebp ; --BUGGY NEW-- shl eax,(ZSHIFT-2) ; --BUGGY NEW-- sar edx,32-(ZSHIFT-2) ; --BUGGY NEW-- idiv ecx ; eax = (v/z) ; --BUGGY NEW-- ; --BUGGY NEW-- mov ecx, U0 ; ecx = U0 until pop's ; --BUGGY NEW-- mov edi, V0 ; edi = V0 until pop's ; --BUGGY NEW-- ; --BUGGY NEW-- shl eax, 16-(ZSHIFT-2) ; --BUGGY NEW-- mov ebp, eax ; ebp = V1 until pop's ; --BUGGY NEW-- ; --BUGGY NEW--; Make ESI = V0:U0 in 6:10,6:10 format ; --BUGGY NEW-- mov eax, ecx ; --BUGGY NEW-- shr eax, 6 ; --BUGGY NEW-- mov esi, edi ; --BUGGY NEW-- shl esi, 10 ; --BUGGY NEW-- mov si, ax ; --BUGGY NEW-- ; --BUGGY NEW--; Make EDX = DV:DU in 6:10,6:10 format ; --BUGGY NEW-- mov eax, ebx ; --BUGGY NEW-- sub eax, ecx ; --BUGGY NEW-- sar eax, (NBITS-2)+6 ; --BUGGY NEW-- mov edx, ebp ; --BUGGY NEW-- sub edx, edi ; --BUGGY NEW-- shl edx, 10-(NBITS-2) ; EDX = V1-V0/ 4 in 6:10 int:frac ; --BUGGY NEW-- mov dx, ax ; put delta u in low word ; --BUGGY NEW-- ; --BUGGY NEW--; Save the U1 and V1 so we don't have to divide on the next iteration ; --BUGGY NEW-- mov U0, ebx ; --BUGGY NEW-- mov V0, ebp ; --BUGGY NEW-- ; --BUGGY NEW-- pop edi ; Restore EDI before using it ; --BUGGY NEW-- ; --BUGGY NEW--; LIGHTING CODE ; --BUGGY NEW-- mov ebx, _fx_l ; --BUGGY NEW-- mov ebp, _fx_dl_dx ; --BUGGY NEW-- ; --BUGGY NEW--;** test _Transparency_on,-1 ; --BUGGY NEW--;** je NDEP_no_trans1 ; --BUGGY NEW-- ; --BUGGY NEW-- REPT 2 ; --BUGGY NEW-- local NDEP_skipa1, NDEP_skipa2 ; --BUGGY NEW-- ; --BUGGY NEW-- mov eax, esi ; get u,v ; --BUGGY NEW-- shr eax, 26 ; shift out all but int(v) ; --BUGGY NEW-- shld ax,si,6 ; shift in u, shifting up v ; --BUGGY NEW-- add esi, edx ; inc u,v ; --BUGGY NEW-- mov al, es:[eax] ; get pixel from source bitmap ; --BUGGY NEW-- cmp al,255 ; --BUGGY NEW-- je NDEP_skipa1 ; --BUGGY NEW-- mov ah, bh ; form lighting table lookup value ; --BUGGY NEW-- add ebx, ebp ; update lighting value ; --BUGGY NEW-- mov al, _gr_fade_table[eax] ; xlat thru lighting table into dest buffer ; --BUGGY NEW-- mov [edi],al ; --BUGGY NEW--NDEP_skipa1: ; --BUGGY NEW-- inc edi ; --BUGGY NEW-- ; --BUGGY NEW--; Do odd pixel ; --BUGGY NEW-- mov eax, esi ; get u,v ; --BUGGY NEW-- shr eax, 26 ; shift out all but int(v) ; --BUGGY NEW-- shld ax,si,6 ; shift in u, shifting up v ; --BUGGY NEW-- add esi, edx ; inc u,v ; --BUGGY NEW-- mov al, es:[eax] ; get pixel from source bitmap ; --BUGGY NEW-- cmp al,255 ; --BUGGY NEW-- je NDEP_skipa2 ; --BUGGY NEW-- mov ah, bh ; form lighting table lookup value ; --BUGGY NEW-- add ebx, ebp ; update lighting value ; --BUGGY NEW-- mov al, _gr_fade_table[eax] ; xlat thru lighting table into dest buffer ; --BUGGY NEW-- mov [edi],al ; --BUGGY NEW--NDEP_skipa2: ; --BUGGY NEW-- inc edi ; --BUGGY NEW-- ; --BUGGY NEW-- ENDM ; --BUGGY NEW-- ; --BUGGY NEW-- mov _fx_l, ebx ; --BUGGY NEW-- pop ebp ; --BUGGY NEW-- pop ecx ; --BUGGY NEW-- pop ebx ; --BUGGY NEW-- dec _loop_count ; --BUGGY NEW-- jnz NDEP_TopOfLoop4 ; --BUGGY NEW-- ; --BUGGY NEW-- test num_left_over, -1 ; --BUGGY NEW-- je _none_to_do ; --BUGGY NEW-- ; --BUGGY NEW--NDEP_1: ; --BUGGY NEW-- mov esi,ebx ; --BUGGY NEW-- ; --BUGGY NEW-- align 4 ; --BUGGY NEW--NDEP_loop: ; --BUGGY NEW-- ; --BUGGY NEW--; compute v coordinate ; --BUGGY NEW-- mov eax, ebp ; get v ; --BUGGY NEW-- mov edx, eax ; --BUGGY NEW-- sar edx, 31 ; --BUGGY NEW-- idiv ecx ; eax = (v/z) ; --BUGGY NEW-- ; --BUGGY NEW-- and eax,3fh ; mask with height-1 ; --BUGGY NEW-- mov ebx,eax ; --BUGGY NEW-- ; --BUGGY NEW--; compute u coordinate ; --BUGGY NEW-- mov eax, esi ; get u ; --BUGGY NEW-- mov edx, eax ; --BUGGY NEW-- sar edx, 31 ; --BUGGY NEW-- idiv ecx ; eax = (u/z) ; --BUGGY NEW-- ; --BUGGY NEW-- shl eax,26 ; --BUGGY NEW-- shld ebx,eax,6 ; esi = v*64+u ; --BUGGY NEW-- ; --BUGGY NEW--; read 1 pixel ; --BUGGY NEW-- xor eax, eax ; --BUGGY NEW-- mov al, es:[ebx] ; get pixel from source bitmap ; --BUGGY NEW-- ; --BUGGY NEW--; lighting code ; --BUGGY NEW-- mov ebx, _fx_l ; get temp copy of lighting value ; --BUGGY NEW-- mov ah, bh ; get lighting level ; --BUGGY NEW-- add ebx, _fx_dl_dx ; update lighting value ; --BUGGY NEW-- mov _fx_l, ebx ; save temp copy of lighting value ; --BUGGY NEW-- ; --BUGGY NEW--; transparency check ; --BUGGY NEW-- cmp al,255 ; --BUGGY NEW-- je NDEP_skip2 ; this pixel is transparent, so don't write it (or light it) ; --BUGGY NEW-- ; --BUGGY NEW-- mov al, _gr_fade_table[eax] ; xlat pixel thru lighting tables ; --BUGGY NEW-- ; --BUGGY NEW--; write 1 pixel ; --BUGGY NEW-- mov [edi],al ; --BUGGY NEW--NDEP_skip2: inc edi ; --BUGGY NEW-- ; --BUGGY NEW--; update deltas ; --BUGGY NEW-- add ebp,_fx_dv_dx ; --BUGGY NEW-- add esi,_fx_du_dx ; --BUGGY NEW-- add ecx,_fx_dz_dx ; --BUGGY NEW-- je _div_0_abort ; would be dividing by 0, so abort ; --BUGGY NEW-- ; --BUGGY NEW-- dec num_left_over ; --BUGGY NEW-- jne NDEP_loop ; --BUGGY NEW-- ; --BUGGY NEW-- jmp _none_to_do NewDoEndPixels: mov esi,ebx align 4 NDEP_loop: ; compute v coordinate mov eax, ebp ; get v mov edx, eax sar edx, 31 idiv ecx ; eax = (v/z) and eax,3fh ; mask with height-1 mov ebx,eax ; compute u coordinate mov eax, esi ; get u mov edx, eax sar edx, 31 idiv ecx ; eax = (u/z) shl eax,26 shld ebx,eax,6 ; esi = v*64+u ; read 1 pixel add ebx,[_pixptr] xor eax, eax mov al, [ebx] ; get pixel from source bitmap ; lighting code mov ebx, [_fx_l] ; get temp copy of lighting value mov ah, bh ; get lighting level add ebx, [_fx_dl_dx] ; update lighting value mov [_fx_l], ebx ; save temp copy of lighting value ; transparency check cmp al,255 je NDEP_skip2 ; this pixel is transparent, so don't write it (or light it) mov al, [_gr_fade_table+eax] ; xlat pixel thru lighting tables ; write 1 pixel mov [edi],al NDEP_skip2: inc edi ; update deltas add ebp,[_fx_dv_dx] add esi,[_fx_du_dx] add ecx,[_fx_dz_dx] je near _div_0_abort ; would be dividing by 0, so abort dec dword [num_left_over] jne NDEP_loop jmp _none_to_do ; ==================================================== No Lighting Code ====================================================== global _tmap_loop_fast_nolight _tmap_loop_fast_nolight: mov esi,ebx align 4 NotDwordAligned1_nolight: test edi, 11b jz DwordAligned1_nolight ; compute v coordinate mov eax,ebp ; get v mov edx, eax sar edx, 31 idiv ecx ; eax = (v/z) and eax,3fh ; mask with height-1 mov ebx,eax ; compute u coordinate mov eax, esi ; get u mov edx, eax sar edx, 31 idiv ecx ; eax = (u/z) shl eax,26 shld ebx,eax,6 ; esi = v*64+u ; read 1 pixel add ebx,[_pixptr] mov al,[ebx] ; get pixel from source bitmap ; write 1 pixel cmp al,255 je skip6 mov [edi],al skip6: inc edi ; update deltas add ebp,[_fx_dv_dx] add esi,[_fx_du_dx] add ecx,[_fx_dz_dx] je near _div_0_abort ; would be dividing by 0, so abort dec dword [_loop_count] jns NotDwordAligned1_nolight jmp _none_to_do DwordAligned1_nolight: mov ebx,esi mov eax, [_loop_count] inc eax mov [num_left_over], eax shr eax, NBITS test eax, -1 je near tmap_loop ; no 2^NBITS chunks, do divide/pixel for whole scanline mov [_loop_count], eax ; _loop_count = pixels / NPIXS shl eax, NBITS sub [num_left_over], eax ; num_left_over = obvious ; compute initial v coordinate mov eax,ebp ; get v ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov [V0], eax ; compute initial u coordinate mov eax,ebx ; get u ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov [U0], eax ; Set deltas to NPIXS pixel increments mov eax, [_fx_du_dx] shl eax, NBITS mov [DU1], eax mov eax, [_fx_dv_dx] shl eax, NBITS mov [DV1], eax mov eax, [_fx_dz_dx] shl eax, NBITS mov [DZ1], eax align 4 TopOfLoop4_nolight: add ebx, [DU1] add ebp, [DV1] add ecx, [DZ1] je near _div_0_abort ; Done with ebx, ebp, ecx until next iteration push ebx push ecx push ebp push edi ; Find fixed U1 mov eax, ebx ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebx, eax ; ebx = U1 until pop's ; Find fixed V1 mov eax, ebp ;PDIV mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebp, eax ; ebp = V1 until pop's mov ecx, [U0] ; ecx = U0 until pop's mov edi, [V0] ; edi = V0 until pop's ; Make ESI = V0:U0 in 6:10,6:10 format mov eax, ecx shr eax, 6 mov esi, edi shl esi, 10 mov si, ax ; Make EDX = DV:DU in 6:10,6:10 format mov eax, ebx sub eax, ecx sar eax, NBITS+6 mov edx, ebp sub edx, edi shl edx, 10-NBITS ; EDX = V1-V0/ 4 in 6:10 int:frac mov dx, ax ; put delta u in low word ; Save the U1 and V1 so we don't have to divide on the next iteration mov [U0], ebx mov [V0], ebp pop edi ; Restore EDI before using it %macro repproc4 0 ; Do 1 pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add esi, edx ; inc u,v add eax,[_pixptr] mov cl, [eax] ; load into buffer register mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] mov ch, [eax] ; load into buffer register add esi, edx ; inc u,v ror ecx, 16 ; move to next dest pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] mov cl, [eax] ; load into buffer register add esi, edx ; inc u,v mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] mov ch, [eax] ; load into buffer register add esi, edx ; inc u,v ror ecx, 16 ;-- can get rid of this, just write in different order below -- ; move to next dest pixel test dword [_Transparency_on],-1 je %%no_trans2 cmp ecx,-1 je %%skip7 cmp cl,255 je %%skip1q mov [edi],cl %%skip1q: cmp ch,255 je %%skip2q mov [edi+1],ch %%skip2q: ror ecx,16 cmp cl,255 je %%skip3q mov [edi+2],cl %%skip3q: cmp ch,255 je %%skip4q mov [edi+3],ch %%skip4q: jmp %%skip7 %%no_trans2: mov [edi],ecx ; Draw 4 pixels to display %%skip7: add edi,4 %endmacro %rep (1 << (NBITS-2)) ;local skip7, no_trans2, skip1q, skip2q, skip3q, skip4q repproc4 %endrep pop ebp pop ecx pop ebx dec dword [_loop_count] jnz near TopOfLoop4_nolight EndOfLoop4_nolight: test dword [num_left_over], -1 je near _none_to_do DoEndPixels_nolight: add ebx, [DU1] add ebp, [DV1] add ecx, [DZ1] je near _div_0_abort push edi ; use edi as a temporary variable ; Find fixed U1 mov eax, ebx mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebx, eax ; ebx = U1 until pop's ; Find fixed V1 mov eax, ebp mov edx,eax shl eax,ZSHIFT sar edx,32-ZSHIFT idiv ecx ; eax = (v/z) shl eax, 16-ZSHIFT mov ebp, eax ; ebp = V1 until pop's mov ecx, [U0] ; ecx = U0 until pop's mov edi, [V0] ; edi = V0 until pop's ; Make ESI = V0:U0 in 6:10,6:10 format mov eax, ecx shr eax, 6 mov esi, edi shl esi, 10 mov si, ax ; Make EDX = DV:DU in 6:10,6:10 format mov eax, ebx sub eax, ecx sar eax, NBITS+6 mov edx, ebp sub edx, edi shl edx, 10-NBITS ; EDX = V1-V0/ 4 in 6:10 int:frac mov dx, ax ; put delta u in low word pop edi ; Restore EDI before using it mov ecx, [num_left_over] %assign ITERATION 0 %macro repproc5 0 ; Do 1 pixel mov eax, esi ; get u,v shr eax, 26 ; shift out all but int(v) shld ax,si,6 ; shift in u, shifting up v add eax,[_pixptr] movzx eax, byte [eax] ; load into buffer register add esi, edx ; inc u,v cmp al,255 je %%skip8 mov [edi+ITERATION], al ; write pixel %%skip8: dec ecx jz near _none_to_do %endmacro %rep (1 << NBITS) ;local skip8 repproc5 %assign ITERATION ITERATION + 1 %endrep ; Should never get here!!!!! int 3 jmp _none_to_do dxx-rebirth-0.58.1-d1x/texmap/tmapfade.asm000077500000000000000000000076341217717257200203500ustar00rootroot00000000000000;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; ; $Source: /cvsroot/dxx-rebirth/d1x-rebirth/texmap/tmapfade.asm,v $ ; $Revision: 1.1.1.1 $ ; $Author: zicodxx $ ; $Date: 2006/03/17 19:46:06 $ ; ; . ; ; $Log: tmapfade.asm,v $ ; Revision 1.1.1.1 2006/03/17 19:46:06 zicodxx ; initial import ; ; Revision 1.1.1.1 1999/06/14 22:13:53 donut ; Import of d1x 1.37 source. ; ; Revision 1.6 1995/02/20 18:23:01 john ; Put all the externs in the assembly modules into tmap_inc.asm. ; Also, moved all the C versions of the inner loops into a new module, ; scanline.c. ; ; Revision 1.5 1995/02/20 17:09:15 john ; Added code so that you can build the tmapper with no assembly! ; ; Revision 1.4 1994/12/02 23:29:36 mike ; change jb/ja to jl/jg. ; ; Revision 1.3 1994/11/30 00:57:36 mike ; *** empty log message *** ; ; Revision 1.2 1994/10/06 18:38:49 john ; Added the ability to fade a scanline by calling gr_upoly_tmap ; with Gr_scanline_darkening_level with a value < MAX_FADE_LEVELS. ; ; Revision 1.1 1994/10/06 18:04:42 john ; Initial revision ; ; [BITS 32] global _asm_tmap_scanline_shaded global asm_tmap_scanline_shaded [SECTION .data] %include "tmap_inc.asm" _loop_count dd 0 [SECTION .text] ; -------------------------------------------------------------------------------------------------- ; Enter: ; _xleft fixed point left x coordinate ; _xright fixed point right x coordinate ; _y fixed point y coordinate ;**; _pixptr address of source pixel map ; for (x = (int) xleft; x <= (int) xright; x++) { ; _setcolor(read_pixel_from_tmap(srcb,((int) (u/z)) & 63,((int) (v/z)) & 63)); ; _setpixel(x,y); ; ; z += dz_dx; ; } align 4 _asm_tmap_scanline_shaded: asm_tmap_scanline_shaded: ; push fs pusha ; mov fs, [_gr_fade_table_selector] ; DPH: No selectors in windows ; Setup for loop: _loop_count iterations = (int) xright - (int) xleft ; edi initial row pointer = y*320+x ; set edi = address of first pixel to modify mov edi,[_fx_y] cmp edi,_window_bottom jae near _none_to_do imul edi,[_bytes_per_row] mov eax,[_fx_xleft] test eax,eax jns eax_ok sub eax,eax eax_ok: add edi,eax add edi,[_write_buffer] ; set _loop_count = # of iterations mov eax,[_fx_xright] cmp eax,[_window_right] jl eax_ok1 mov eax,[_window_right] eax_ok1: cmp eax,[_window_left] jg eax_ok2 mov eax,[_window_left] eax_ok2: mov ebx,[_fx_xleft] sub eax,ebx js near _none_to_do cmp eax,[_window_width] jbe _ok_to_do mov eax,[_window_width] _ok_to_do: mov [_loop_count], eax mov ecx, 0 mov ch,[_tmap_flat_shade_value] and ch, 31 ;_size = (_end1 - _start1)/num_iters mov eax,num_iters-1 sub eax,[_loop_count] jns j_eax_ok1 inc eax ; sort of a hack, but we can get -1 here and want to be graceful jns j_eax_ok1 ; if we jump, we had -1, which is kind of ok, if not, we int 3 int 3 ; oops, going to jump behind _start1, very bad... sub eax,eax ; ok to continue j_eax_ok1: imul eax,eax,(_end1 - _start1)/num_iters add eax, _start1 ;originally offset _start1 jmp eax align 4 _start1: %rep num_iters mov cl, [edi] ; get pixel mov al, [_gr_fade_table + ecx] ; darken pixel mov [edi], al ; write pixel inc edi ; goto next pixel %endrep _end1: _none_to_do: popa ; pop fs ret dxx-rebirth-0.58.1-d1x/texmap/tmapflat.c000066400000000000000000000151251217717257200200300ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Flat shader derived from texture mapper (a little slow) * */ #include #include #include #include #include "maths.h" #include "gr.h" #include "grdef.h" #include "texmap.h" #include "texmapl.h" #include "scanline.h" #ifndef OGL void (*scanline_func)(int,fix,fix); // ------------------------------------------------------------------------------------- // Texture map current scanline. // Uses globals Du_dx and Dv_dx to incrementally compute u,v coordinates // ------------------------------------------------------------------------------------- void tmap_scanline_flat(int y, fix xleft, fix xright) { if (xright < xleft) return; // setup to call assembler scanline renderer fx_y = y; fx_xleft = xleft/F1_0; // (xleft >> 16) != xleft/F1_0 for negative numbers, f2i caused random crashes fx_xright = xright/F1_0; if ( grd_curcanv->cv_fade_level >= GR_FADE_OFF ) cur_tmap_scanline_flat(); else { tmap_flat_shade_value = grd_curcanv->cv_fade_level; cur_tmap_scanline_shaded(); } } // ------------------------------------------------------------------------------------- // Render a texture map. // Linear in outer loop, linear in inner loop. // ------------------------------------------------------------------------------------- void texture_map_flat(g3ds_tmap *t, int color) { int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom int topy,boty,y, dy; fix dx_dy_left,dx_dy_right; int max_y_vertex; fix xleft,xright; fix recip_dy; g3ds_vertex *v3d; v3d = t->verts; tmap_flat_color = color; // Determine top and bottom y coords. compute_y_bounds(t,&vlt,&vlb,&vrt,&vrb,&max_y_vertex); // Set top and bottom (of entire texture map) y coordinates. topy = f2i(v3d[vlt].y2d); boty = f2i(v3d[max_y_vertex].y2d); // Set amount to change x coordinate for each advance to next scanline. dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); // Set initial values for x, u, v xleft = v3d[vlt].x2d; xright = v3d[vrt].x2d; // scan all rows in texture map from top through first break. // @mk: Should we render the scanline for y==boty? This violates Matt's spec. for (y = topy; y < boty; y++) { // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x,u,v if (y == f2i(v3d[vlb].y2d)) { // Handle problem of double points. Search until y coord is different. Cannot get // hung in an infinite loop because we know there is a vertex with a lower y coordinate // because in the for loop, we don't scan all spanlines. while (y == f2i(v3d[vlb].y2d)) { vlt = vlb; vlb = prevmod(vlb,t->nv); } dy = f2i(t->verts[vlb].y2d) - f2i(t->verts[vlt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy); xleft = v3d[vlt].x2d; } // See if we have reached the end of the current left edge, and if so, set // new values for dx_dy and x. Not necessary to set new values for u,v. if (y == f2i(v3d[vrb].y2d)) { while (y == f2i(v3d[vrb].y2d)) { vrt = vrb; vrb = succmod(vrb,t->nv); } dy = f2i(t->verts[vrb].y2d) - f2i(t->verts[vrt].y2d); if (dy < FIX_RECIP_TABLE_SIZE) recip_dy = fix_recip[dy]; else recip_dy = F1_0/dy; dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy); xright = v3d[vrt].x2d; } //tmap_scanline_flat(y, xleft, xright); (*scanline_func)(y, xleft, xright); xleft += dx_dy_left; xright += dx_dy_right; } //tmap_scanline_flat(y, xleft, xright); (*scanline_func)(y, xleft, xright); } // ----------------------------------------------------------------------------------------- // This is the gr_upoly-like interface to the texture mapper which uses texture-mapper compatible // (ie, avoids cracking) edge/delta computation. void gr_upoly_tmap(int nverts, int *vert ) { gr_upoly_tmap_ylr(nverts, vert, tmap_scanline_flat); } #include "3d.h" #include "dxxerror.h" typedef struct pnt2d { fix x,y; } pnt2d; #ifdef __WATCOMC__ #pragma off (unreferenced) //bp not referenced #endif //this takes the same partms as draw_tmap, but draws a flat-shaded polygon void draw_tmap_flat(grs_bitmap *bp,int nverts,g3s_point **vertbuf) { pnt2d points[MAX_TMAP_VERTS]; int i; fix average_light; int color; Assert(nverts < MAX_TMAP_VERTS); average_light = vertbuf[0]->p3_l; for (i=1; ip3_l; if (nverts == 4) average_light = f2i(average_light * NUM_LIGHTING_LEVELS/4); else average_light = f2i(average_light * NUM_LIGHTING_LEVELS/nverts); if (average_light < 0) average_light = 0; else if (average_light > NUM_LIGHTING_LEVELS-1) average_light = NUM_LIGHTING_LEVELS-1; color = gr_fade_table[average_light*256 + bp->avg_color]; gr_setcolor(color); for (i=0;ip3_sx; points[i].y = vertbuf[i]->p3_sy; } gr_upoly_tmap(nverts,(int *) points); } #ifdef __WATCOMC__ #pragma on (unreferenced) #endif // ----------------------------------------------------------------------------------------- //This is like gr_upoly_tmap() but instead of drawing, it calls the specified //function with ylr values void gr_upoly_tmap_ylr(int nverts, int *vert, void (*ylr_func)(int,fix,fix) ) { g3ds_tmap my_tmap; int i; //--now called from g3_start_frame-- init_interface_vars_to_assembler(); my_tmap.nv = nverts; for (i=0; i #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #define Middle(x) ((2*(x)+1)/4) #define BUTTON_EXTRA_WIDTH 15 #define BUTTON_EXTRA_HEIGHT 2 int ui_button_any_drawn = 0; void ui_get_button_size( char * text, int * width, int * height ) { int avg; gr_get_string_size(text, width, height, &avg ); *width += BUTTON_EXTRA_WIDTH*2; *width += 6; *height += BUTTON_EXTRA_HEIGHT*2; *height += 6; } void ui_draw_button(UI_DIALOG *dlg, UI_GADGET_BUTTON * button) { int color; #if 0 //ndef OGL if ((button->status==1) || (button->position != button->oldposition)) #endif { ui_button_any_drawn = 1; gr_set_current_canvas( button->canvas ); color = button->canvas->cv_color; if (dlg->keyboard_focus_gadget == (UI_GADGET *)button) gr_set_fontcolor( CRED, -1 ); else { if ((button->user_function==NULL) && button->dim_if_no_function ) gr_set_fontcolor( CGREY, -1 ); else gr_set_fontcolor( CBLACK, -1 ); } button->status = 0; if (button->position == 0 ) { if (button->text ) { ui_draw_box_out( 0, 0, button->width-1, button->height-1 ); ui_string_centered( Middle(button->width), Middle(button->height), button->text ); } else { gr_setcolor( CBLACK ); gr_rect( 0, 0, button->width, button->height ); gr_setcolor( color ); gr_rect( 1, 1, button->width-1, button->height-1 ); } } else { if (button->text ) { ui_draw_box_in( 0, 0, button->width-1, button->height-1 ); ui_string_centered( Middle(button->width)+1, Middle(button->height)+1, button->text ); } else { gr_setcolor( CBLACK ); gr_rect( 0, 0, button->width, button->height ); gr_setcolor( color ); gr_rect( 2, 2, button->width, button->height ); } } button->canvas->cv_color = color; } } UI_GADGET_BUTTON * ui_add_gadget_button( UI_DIALOG * dlg, short x, short y, short w, short h, char * text, int (*function_to_call)(void) ) { UI_GADGET_BUTTON * button; button = (UI_GADGET_BUTTON *)ui_gadget_add( dlg, 1, x, y, x+w-1, y+h-1 ); if ( text ) { MALLOC( button->text, char, strlen(text)+1 ); strcpy( button->text, text ); } else { button->text = NULL; } button->width = w; button->height = h; button->position = 0; button->oldposition = 0; button->pressed = 0; button->user_function = function_to_call; button->user_function1 = NULL; button->hotkey1= -1; button->dim_if_no_function = 0; return button; } int ui_button_do(UI_DIALOG *dlg, UI_GADGET_BUTTON * button, d_event *event) { int rval = 0; button->oldposition = button->position; button->pressed = 0; if (event->type == EVENT_MOUSE_BUTTON_DOWN || event->type == EVENT_MOUSE_BUTTON_UP) { int OnMe; OnMe = ui_mouse_on_gadget( (UI_GADGET *)button ); if (B1_JUST_PRESSED && OnMe) { button->position = 1; rval = 1; } else if (B1_JUST_RELEASED) { if ((button->position == 1) && OnMe) button->pressed = 1; button->position = 0; } } if (event->type == EVENT_KEY_COMMAND) { int keypress; keypress = event_key_get(event); if ((keypress == button->hotkey) || ((keypress == button->hotkey1) && button->user_function1) || ((dlg->keyboard_focus_gadget==(UI_GADGET *)button) && ((keypress==KEY_SPACEBAR) || (keypress==KEY_ENTER)) )) { button->position = 2; rval = 1; } } else if (event->type == EVENT_KEY_RELEASE) { int keypress; keypress = event_key_get(event); button->position = 0; if ((keypress == button->hotkey) || ((dlg->keyboard_focus_gadget==(UI_GADGET *)button) && ((keypress==KEY_SPACEBAR) || (keypress==KEY_ENTER)) )) button->pressed = 1; if ((keypress == button->hotkey1) && button->user_function1) { button->user_function1(); rval = 1; } } if (event->type == EVENT_WINDOW_DRAW) ui_draw_button( dlg, button ); if (button->pressed && button->user_function ) { button->user_function(); rval = 1; } else if (button->pressed) { ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)button); rval = 1; } return rval; } dxx-rebirth-0.58.1-d1x/ui/checkbox.c000066400000000000000000000076151217717257200171320ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #define Middle(x) ((2*(x)+1)/4) void ui_draw_checkbox( UI_DIALOG *dlg, UI_GADGET_CHECKBOX * checkbox ) { #if 0 //ndef OGL if ((checkbox->status==1) || (checkbox->position != checkbox->oldposition)) #endif { checkbox->status = 0; gr_set_current_canvas( checkbox->canvas ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)checkbox) gr_set_fontcolor( CRED, -1 ); else gr_set_fontcolor( CBLACK, -1 ); if (checkbox->position == 0 ) { ui_draw_box_out( 0, 0, checkbox->width-1, checkbox->height-1 ); if (checkbox->flag) ui_string_centered( Middle(checkbox->width), Middle(checkbox->height), "X" ); else ui_string_centered( Middle(checkbox->width), Middle(checkbox->height), " " ); } else { ui_draw_box_in( 0, 0, checkbox->width-1, checkbox->height-1 ); if (checkbox->flag) ui_string_centered( Middle(checkbox->width)+1, Middle(checkbox->height)+1, "X" ); else ui_string_centered( Middle(checkbox->width)+1, Middle(checkbox->height)+1, " " ); } gr_ustring( checkbox->width+4, 2, checkbox->text ); } } UI_GADGET_CHECKBOX * ui_add_gadget_checkbox( UI_DIALOG * dlg, short x, short y, short w, short h, short group, char * text ) { UI_GADGET_CHECKBOX * checkbox; checkbox = (UI_GADGET_CHECKBOX *)ui_gadget_add( dlg, 5, x, y, x+w-1, y+h-1 ); checkbox->text = d_malloc(strlen(text) + 5); strcpy(checkbox->text,text); checkbox->width = w; checkbox->height = h; checkbox->position = 0; checkbox->oldposition = 0; checkbox->pressed = 0; checkbox->flag = 0; checkbox->group = group; return checkbox; } int ui_checkbox_do( UI_DIALOG *dlg, UI_GADGET_CHECKBOX * checkbox, d_event *event ) { int rval = 0; checkbox->oldposition = checkbox->position; checkbox->pressed = 0; if (event->type == EVENT_MOUSE_BUTTON_DOWN || event->type == EVENT_MOUSE_BUTTON_UP) { int OnMe; OnMe = ui_mouse_on_gadget( (UI_GADGET *)checkbox ); if (B1_JUST_PRESSED && OnMe) { checkbox->position = 1; rval = 1; } else if (B1_JUST_RELEASED) { if ((checkbox->position==1) && OnMe) checkbox->pressed = 1; checkbox->position = 0; } } if (event->type == EVENT_KEY_COMMAND) { int key; key = event_key_get(event); if ((dlg->keyboard_focus_gadget==(UI_GADGET *)checkbox) && ((key==KEY_SPACEBAR) || (key==KEY_ENTER)) ) { checkbox->position = 2; rval = 1; } } else if (event->type == EVENT_KEY_RELEASE) { int key; key = event_key_get(event); checkbox->position = 0; if ((dlg->keyboard_focus_gadget==(UI_GADGET *)checkbox) && ((key==KEY_SPACEBAR) || (key==KEY_ENTER)) ) checkbox->pressed = 1; } if (checkbox->pressed == 1) { checkbox->flag ^= 1; ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)checkbox); rval = 1; } if (event->type == EVENT_WINDOW_DRAW) ui_draw_checkbox( dlg, checkbox ); return rval; } void ui_checkbox_check(UI_GADGET_CHECKBOX * checkbox, int check) { check = check != 0; if (checkbox->flag == check) return; checkbox->flag = check; checkbox->status = 1; // redraw } dxx-rebirth-0.58.1-d1x/ui/dialog.c000066400000000000000000000301441217717257200165740ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Windowing functions and controller. * */ #include #include #include #include "window.h" #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "ui.h" #include "key.h" #include "mouse.h" #include "timer.h" #include "dxxerror.h" #define D_X (dlg->x) #define D_Y (dlg->y) #define D_WIDTH (dlg->width) #define D_HEIGHT (dlg->height) #define D_GADGET (dlg->gadget) #define D_TEXT_X (dlg->text_x) #define D_TEXT_Y (dlg->text_y) #ifndef __MSDOS__ #define _disable() #define _enable() #endif #define BORDER_WIDTH 8 static unsigned int FrameCount = 0; unsigned int ui_event_counter = 0; unsigned int ui_number_of_events = 0; static UI_EVENT * EventBuffer = NULL; static int Record = 0; static int RecordFlags = 0; static unsigned char SavedState[256]; static int PlaybackSpeed = 1; // 1=1x faster, 2=2x faster, etc void ui_set_playback_speed( int speed ) { PlaybackSpeed = speed; } int ui_record_events( int NumberOfEvents, UI_EVENT * buffer, int Flags ) { if ( Record > 0 || buffer==NULL ) return 1; RecordFlags = Flags; EventBuffer = buffer; ui_event_counter = 0; FrameCount = 0; ui_number_of_events = NumberOfEvents; Record = 1; return 0; } int ui_play_events_realtime( int NumberOfEvents, UI_EVENT * buffer ) { int i; if ( buffer == NULL ) return 1; EventBuffer = buffer; FrameCount = 0; ui_event_counter = 0; ui_number_of_events = NumberOfEvents; Record = 2; _disable(); keyd_last_released= 0; keyd_last_pressed= 0; for (i=0; i<256; i++ ) SavedState[i] = keyd_pressed[i]; _enable(); key_flush(); return 0; } int ui_play_events_fast( int NumberOfEvents, UI_EVENT * buffer ) { int i; if ( buffer == NULL ) return 1; EventBuffer = buffer; FrameCount = 0; ui_event_counter = 0; ui_number_of_events = NumberOfEvents; Record = 3; _disable(); keyd_last_released= 0; keyd_last_pressed= 0; for (i=0; i<256; i++ ) { SavedState[i] = keyd_pressed[i]; } _enable(); key_flush(); return 0; } // Returns: 0=Normal, 1=Recording, 2=Playback normal, 3=Playback fast int ui_recorder_status() { return Record; } void ui_dialog_draw(UI_DIALOG *dlg) { int x, y, w, h; int req_w, req_h; x = D_X; y = D_Y; w = D_WIDTH; h = D_HEIGHT; req_w = w; req_h = h; if (dlg->flags & DF_BORDER) { req_w -= 2*BORDER_WIDTH; req_h -= 2*BORDER_WIDTH; gr_set_current_canvas( NULL ); ui_draw_frame( x, y, x+w-1, y+h-1 ); } ui_dialog_set_current_canvas(dlg); if (dlg->flags & DF_FILLED) ui_draw_box_out( 0, 0, req_w-1, req_h-1 ); gr_set_fontcolor( CBLACK, CWHITE ); D_TEXT_X = 0; D_TEXT_Y = 0; } // The dialog handler borrows heavily from the newmenu_handler int ui_dialog_handler(window *wind, d_event *event, UI_DIALOG *dlg) { int rval = 0; if (event->type == EVENT_WINDOW_CLOSED || event->type == EVENT_WINDOW_ACTIVATED || event->type == EVENT_WINDOW_DEACTIVATED) return 0; if (dlg->callback) if ((*dlg->callback)(dlg, event, dlg->userdata)) return 1; // event handled if (!window_exists(wind)) return 1; switch (event->type) { case EVENT_MOUSE_BUTTON_DOWN: case EVENT_MOUSE_BUTTON_UP: case EVENT_MOUSE_MOVED: /*return*/ ui_dialog_do_gadgets(dlg, event); if (!window_exists(wind)) return 1; rval = mouse_in_window(dlg->wind); break; case EVENT_KEY_COMMAND: case EVENT_KEY_RELEASE: rval = ui_dialog_do_gadgets(dlg, event); break; case EVENT_IDLE: timer_delay2(50); rval = ui_dialog_do_gadgets(dlg, event); break; case EVENT_WINDOW_DRAW: { d_event event2 = { EVENT_UI_DIALOG_DRAW }; ui_dialog_draw(dlg); rval = ui_dialog_do_gadgets(dlg, event); window_send_event(wind, &event2); break; } case EVENT_WINDOW_CLOSE: ui_gadget_delete_all(dlg); selected_gadget = NULL; d_free( dlg ); break; default: break; } return rval; } UI_DIALOG * ui_create_dialog( short x, short y, short w, short h, enum dialog_flags flags, int (*callback)(UI_DIALOG *, d_event *, void *), void *userdata ) { UI_DIALOG *dlg; int sw, sh, req_w, req_h; dlg = (UI_DIALOG *) d_malloc(sizeof(UI_DIALOG)); if (dlg==NULL) Error("Could not create dialog: Out of memory"); sw = grd_curscreen->sc_w; sh = grd_curscreen->sc_h; //mouse_set_limits(0, 0, sw - 1, sh - 1); req_w = w; req_h = h; dlg->flags = flags; if (flags & DF_BORDER) { x -= BORDER_WIDTH; y -= BORDER_WIDTH; w += 2*BORDER_WIDTH; h += 2*BORDER_WIDTH; } if ( x < 0 ) x = 0; if ( (x+w-1) >= sw ) x = sw - w; if ( y < 0 ) y = 0; if ( (y+h-1) >= sh ) y = sh - h; D_X = x; D_Y = y; D_WIDTH = w; D_HEIGHT = h; D_GADGET = NULL; dlg->keyboard_focus_gadget = NULL; selected_gadget = NULL; dlg->callback = callback; dlg->userdata = userdata; dlg->wind = window_create(&grd_curscreen->sc_canvas, x + ((flags & DF_BORDER) ? BORDER_WIDTH : 0), y + ((flags & DF_BORDER) ? BORDER_WIDTH : 0), req_w, req_h, (int (*)(window *, d_event *, void *)) ui_dialog_handler, dlg); if (!dlg->wind) { d_free(dlg); return NULL; } if (!(flags & DF_MODAL)) window_set_modal(dlg->wind, 0); // make this window modeless, allowing events to propogate through the window stack return dlg; } window *ui_dialog_get_window(UI_DIALOG *dlg) { return dlg->wind; } void ui_dialog_set_current_canvas(UI_DIALOG *dlg) { gr_set_current_canvas(window_get_canvas(dlg->wind)); } void ui_close_dialog( UI_DIALOG * dlg ) { window_close(dlg->wind); } void restore_state() { int i; _disable(); for (i=0; i<256; i++ ) { keyd_pressed[i] = SavedState[i]; } _enable(); } #if 0 void ui_mega_process() { int mx, my, mz; unsigned char k; event_process(); switch( Record ) { case 0: mouse_get_delta( &mx, &my, &mz ); Mouse.new_dx = mx; Mouse.new_dy = my; Mouse.new_buttons = mouse_get_btns(); last_keypress = key_inkey(); if ( Mouse.new_buttons || last_keypress || Mouse.new_dx || Mouse.new_dy ) { last_event = timer_query(); } break; case 1: if (ui_event_counter==0 ) { EventBuffer[ui_event_counter].frame = 0; EventBuffer[ui_event_counter].type = 7; EventBuffer[ui_event_counter].data = ui_number_of_events; ui_event_counter++; } if (ui_event_counter==1 && (RecordFlags & UI_RECORD_MOUSE) ) { Mouse.new_buttons = 0; EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 6; EventBuffer[ui_event_counter].data = ((Mouse.y & 0xFFFF) << 16) | (Mouse.x & 0xFFFF); ui_event_counter++; } mouse_get_delta( &mx, &my, &mz ); MouseDX = mx; MouseDY = my; MouseButtons = mouse_get_btns(); Mouse.new_dx = MouseDX; Mouse.new_dy = MouseDY; if ((MouseDX != 0 || MouseDY != 0) && (RecordFlags & UI_RECORD_MOUSE) ) { if (ui_event_counter < ui_number_of_events-1 ) { EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 1; EventBuffer[ui_event_counter].data = ((MouseDY & 0xFFFF) << 16) | (MouseDX & 0xFFFF); ui_event_counter++; } else { Record = 0; } } if ( (MouseButtons != Mouse.new_buttons) && (RecordFlags & UI_RECORD_MOUSE) ) { Mouse.new_buttons = MouseButtons; if (ui_event_counter < ui_number_of_events-1 ) { EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 2; EventBuffer[ui_event_counter].data = MouseButtons; ui_event_counter++; } else { Record = 0; } } if ( keyd_last_pressed && (RecordFlags & UI_RECORD_KEYS) ) { _disable(); k = keyd_last_pressed; keyd_last_pressed= 0; _enable(); if (ui_event_counter < ui_number_of_events-1 ) { EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 3; EventBuffer[ui_event_counter].data = k; ui_event_counter++; } else { Record = 0; } } if ( keyd_last_released && (RecordFlags & UI_RECORD_KEYS) ) { _disable(); k = keyd_last_released; keyd_last_released= 0; _enable(); if (ui_event_counter < ui_number_of_events-1 ) { EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 4; EventBuffer[ui_event_counter].data = k; ui_event_counter++; } else { Record = 0; } } last_keypress = key_inkey(); if (last_keypress == KEY_F12 ) { ui_number_of_events = ui_event_counter; last_keypress = 0; Record = 0; break; } if ((last_keypress != 0) && (RecordFlags & UI_RECORD_KEYS) ) { if (ui_event_counter < ui_number_of_events-1 ) { EventBuffer[ui_event_counter].frame = FrameCount; EventBuffer[ui_event_counter].type = 5; EventBuffer[ui_event_counter].data = last_keypress; ui_event_counter++; } else { Record = 0; } } FrameCount++; break; case 2: case 3: Mouse.new_dx = 0; Mouse.new_dy = 0; Mouse.new_buttons = 0; last_keypress = 0; if ( keyd_last_pressed ) { _disable(); k = keyd_last_pressed; keyd_last_pressed = 0; _disable(); SavedState[k] = 1; } if ( keyd_last_released ) { _disable(); k = keyd_last_released; keyd_last_released = 0; _disable(); SavedState[k] = 0; } if (key_inkey() == KEY_F12 ) { restore_state(); Record = 0; break; } if (EventBuffer==NULL) { restore_state(); Record = 0; break; } while( (ui_event_counter < ui_number_of_events) && (EventBuffer[ui_event_counter].frame <= FrameCount) ) { switch ( EventBuffer[ui_event_counter].type ) { case 1: // Mouse moved Mouse.new_dx = EventBuffer[ui_event_counter].data & 0xFFFF; Mouse.new_dy = (EventBuffer[ui_event_counter].data >> 16) & 0xFFFF; break; case 2: // Mouse buttons changed Mouse.new_buttons = EventBuffer[ui_event_counter].data; break; case 3: // Key moved down keyd_pressed[ EventBuffer[ui_event_counter].data ] = 1; break; case 4: // Key moved up keyd_pressed[ EventBuffer[ui_event_counter].data ] = 0; break; case 5: // Key pressed last_keypress = EventBuffer[ui_event_counter].data; break; case 6: // Initial Mouse X position Mouse.x = EventBuffer[ui_event_counter].data & 0xFFFF; Mouse.y = (EventBuffer[ui_event_counter].data >> 16) & 0xFFFF; break; case 7: break; } ui_event_counter++; if (ui_event_counter >= ui_number_of_events ) { Record = 0; restore_state(); //( 0, "Done playing %d events.\n", ui_number_of_events ); } } switch (Record) { case 2: { int next_frame; if ( ui_event_counter < ui_number_of_events ) { next_frame = EventBuffer[ui_event_counter].frame; if ( (FrameCount+PlaybackSpeed) < next_frame ) FrameCount = next_frame - PlaybackSpeed; else FrameCount++; } else { FrameCount++; } } break; case 3: if ( ui_event_counter < ui_number_of_events ) FrameCount = EventBuffer[ui_event_counter].frame; else FrameCount++; break; default: FrameCount++; } } ui_mouse_process(); } #endif // 0 void ui_dprintf( UI_DIALOG * dlg, char * format, ... ) { char buffer[1000]; va_list args; va_start(args, format ); vsprintf(buffer,format,args); ui_dialog_set_current_canvas( dlg ); D_TEXT_X = gr_string( D_TEXT_X, D_TEXT_Y, buffer ); } void ui_dprintf_at( UI_DIALOG * dlg, short x, short y, char * format, ... ) { char buffer[1000]; va_list args; va_start(args, format ); vsprintf(buffer,format,args); ui_dialog_set_current_canvas( dlg ); gr_string( x, y, buffer ); } dxx-rebirth-0.58.1-d1x/ui/file.c000066400000000000000000000212441217717257200162550ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "event.h" #include "physfsx.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "key.h" #include "mouse.h" #include "strutil.h" #include "ui.h" #include "window.h" #include "u_mem.h" int file_sort_func(char **e0, char **e1) { return d_stricmp(*e0, *e1); } char **file_getdirlist(int *NumDirs, char *dir) { char path[PATH_MAX]; char **list = PHYSFS_enumerateFiles(dir); char **i, **j = list; char *test_filename; int test_max; if (!list) return NULL; strcpy(path, dir); if (*path) strncat(path, "/", PATH_MAX - strlen(dir)); test_filename = path + strlen(path); test_max = PATH_MAX - (test_filename - path); for (i = list; *i; i++) { if (strlen(*i) >= test_max) continue; strcpy(test_filename, *i); if (PHYSFS_isDirectory(path)) *j++ = *i; else free(*i); } *j = NULL; *NumDirs = j - list; qsort(list, *NumDirs, sizeof(char *), (int (*)( const void *, const void * ))file_sort_func); if (*dir) { // Put the 'go to parent directory' sequence '..' first (*NumDirs)++; list = realloc(list, sizeof(char *)*(*NumDirs + 1)); list[*NumDirs] = NULL; // terminate for (i = list + *NumDirs - 1; i != list; i--) *i = i[-1]; list[0] = strdup(".."); } return list; } char **file_getfilelist(int *NumFiles, char *filespec, char *dir) { char **list = PHYSFS_enumerateFiles(dir); char **i, **j = list, *ext; if (!list) return NULL; if (*filespec == '*') filespec++; for (i = list; *i; i++) { ext = strrchr(*i, '.'); if (ext && (!d_stricmp(ext, filespec))) *j++ = *i; else free(*i); } *j = NULL; *NumFiles = j - list; qsort(list, *NumFiles, sizeof(char *), (int (*)( const void *, const void * ))file_sort_func); return list; } typedef struct browser { char view_dir[PATH_MAX]; char *filename; char *filespec; char *message; char **filename_list; char **directory_list; UI_GADGET_BUTTON *button1, *button2, *help_button; UI_GADGET_LISTBOX *listbox1; UI_GADGET_LISTBOX *listbox2; UI_GADGET_INPUTBOX *user_file; int num_files, num_dirs; char spaces[35]; } browser; static int browser_handler(UI_DIALOG *dlg, d_event *event, browser *b) { int rval = 0; if (event->type == EVENT_UI_DIALOG_DRAW) { ui_dprintf_at( dlg, 10, 5, "%s", b->message ); ui_dprintf_at( dlg, 20, 32,"N&ame" ); ui_dprintf_at( dlg, 20, 86,"&Files" ); ui_dprintf_at( dlg, 210, 86,"&Dirs" ); ui_dprintf_at( dlg, 20, 60, "%s", b->spaces ); ui_dprintf_at( dlg, 20, 60, "%s", b->view_dir ); return 1; } if (GADGET_PRESSED(b->button2)) { PHYSFS_freeList(b->filename_list); b->filename_list = NULL; PHYSFS_freeList(b->directory_list); b->directory_list = NULL; ui_close_dialog(dlg); return 1; } if (GADGET_PRESSED(b->help_button)) { ui_messagebox( -1, -1, 1, "Sorry, no help is available!", "Ok" ); rval = 1; } if (event->type == EVENT_UI_LISTBOX_MOVED) { if ((ui_event_get_gadget(event) == (UI_GADGET *)b->listbox1) && (b->listbox1->current_item >= 0) && b->filename_list[b->listbox1->current_item]) ui_inputbox_set_text(b->user_file, b->filename_list[b->listbox1->current_item]); if ((ui_event_get_gadget(event) == (UI_GADGET *)b->listbox2) && (b->listbox2->current_item >= 0) && b->directory_list[b->listbox2->current_item]) ui_inputbox_set_text(b->user_file, b->directory_list[b->listbox2->current_item]); rval = 1; } if (GADGET_PRESSED(b->button1) || GADGET_PRESSED(b->user_file) || (event->type == EVENT_UI_LISTBOX_SELECTED)) { char *p; if (ui_event_get_gadget(event) == (UI_GADGET *)b->listbox2) strcpy(b->user_file->text, b->directory_list[b->listbox2->current_item]); strncpy(b->filename, b->view_dir, PATH_MAX); p = b->user_file->text; while (!strncmp(p, "..", 2)) // shorten the path manually { char *sep = strrchr(b->filename, '/'); if (sep) *sep = 0; else *b->filename = 0; // look directly in search paths p += 2; if (*p == '/') p++; } if (*b->filename && *p) strncat(b->filename, "/", PATH_MAX - strlen(b->filename)); strncat(b->filename, p, PATH_MAX - strlen(b->filename)); if (!PHYSFS_isDirectory(b->filename)) { PHYSFS_file *TempFile; TempFile = PHYSFS_openRead(b->filename); if (TempFile) { // Looks like a valid filename that already exists! PHYSFS_close(TempFile); ui_close_dialog(dlg); return 1; } // File doesn't exist, but can we create it? TempFile = PHYSFS_openWrite(b->filename); if (TempFile) { // Looks like a valid filename! PHYSFS_close(TempFile); PHYSFS_delete(b->filename); ui_close_dialog(dlg); return 1; } } else { if (b->filename[strlen(b->filename) - 1] == '/') // user typed a separator on the end b->filename[strlen(b->filename) - 1] = 0; strcpy(b->view_dir, b->filename); PHYSFS_freeList(b->filename_list); b->filename_list = file_getfilelist(&b->num_files, b->filespec, b->view_dir); if (!b->filename_list) { PHYSFS_freeList(b->directory_list); b->directory_list = NULL; ui_close_dialog(dlg); return 1; } ui_inputbox_set_text(b->user_file, b->filespec); PHYSFS_freeList(b->directory_list); b->directory_list = file_getdirlist(&b->num_dirs, b->view_dir); if (!b->directory_list) { PHYSFS_freeList(b->filename_list); b->filename_list = NULL; ui_close_dialog(dlg); return 1; } ui_listbox_change(dlg, b->listbox1, b->num_files, b->filename_list); ui_listbox_change(dlg, b->listbox2, b->num_dirs, b->directory_list); //i = TICKER; //while ( TICKER < i+2 ); } rval = 1; } return rval; } int ui_get_filename( char * filename, char * filespec, char * message ) { char InputText[PATH_MAX]; char *p; int i; browser *b; UI_DIALOG *dlg; window *wind; int rval = 0; MALLOC(b, browser, 1); if (!b) return 0; if ((p = strrchr(filename, '/'))) { *p++ = 0; strcpy(b->view_dir, filename); strcpy(InputText, p); } else { strcpy(b->view_dir, ""); strcpy(InputText, filename); } b->filename_list = file_getfilelist(&b->num_files, filespec, b->view_dir); if (!b->filename_list) { d_free(b); return 0; } b->directory_list = file_getdirlist(&b->num_dirs, b->view_dir); if (!b->directory_list) { PHYSFS_freeList(b->filename_list); d_free(b); return 0; } //ui_messagebox( -2,-2, 1,"DEBUG:0", "Ok" ); for (i=0; i<35; i++) b->spaces[i] = ' '; b->spaces[34] = 0; dlg = ui_create_dialog( 200, 100, 400, 370, DF_DIALOG | DF_MODAL, (int (*)(UI_DIALOG *, d_event *, void *))browser_handler, b ); b->user_file = ui_add_gadget_inputbox( dlg, 60, 30, PATH_MAX, 40, InputText ); b->listbox1 = ui_add_gadget_listbox(dlg, 20, 110, 125, 200, b->num_files, b->filename_list); b->listbox2 = ui_add_gadget_listbox(dlg, 210, 110, 100, 200, b->num_dirs, b->directory_list); b->button1 = ui_add_gadget_button( dlg, 20, 330, 60, 25, "Ok", NULL ); b->button2 = ui_add_gadget_button( dlg, 100, 330, 60, 25, "Cancel", NULL ); b->help_button = ui_add_gadget_button( dlg, 180, 330, 60, 25, "Help", NULL ); dlg->keyboard_focus_gadget = (UI_GADGET *)b->user_file; b->button1->hotkey = KEY_CTRLED + KEY_ENTER; b->button2->hotkey = KEY_ESC; b->help_button->hotkey = KEY_F1; b->listbox1->hotkey = KEY_ALTED + KEY_F; b->listbox2->hotkey = KEY_ALTED + KEY_D; b->user_file->hotkey = KEY_ALTED + KEY_A; ui_gadget_calc_keys(dlg); b->filename = filename; b->filespec = filespec; b->message = message; wind = ui_dialog_get_window(dlg); while (window_exists(wind)) event_process(); //key_flush(); if (b->filename_list) PHYSFS_freeList(b->filename_list); if (b->directory_list) PHYSFS_freeList(b->directory_list); rval = b->filename_list != NULL; d_free(b); return rval; } int ui_get_file( char * filename, char * Filespec ) { int x, NumFiles; char **list = file_getfilelist(&NumFiles, Filespec, ""); if (!list) return 0; x = MenuX(-1, -1, NumFiles, list); if (x > 0) strcpy(filename, list[x - 1]); PHYSFS_freeList(list); return (x > 0); } dxx-rebirth-0.58.1-d1x/ui/gadget.c000066400000000000000000000211741217717257200165730ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "ui.h" #include "event.h" #include "mouse.h" #include "window.h" #include "dxxerror.h" #include "key.h" UI_GADGET * selected_gadget; typedef struct event_gadget { event_type type; UI_GADGET *gadget; } event_gadget; UI_GADGET * ui_gadget_add( UI_DIALOG * dlg, short kind, short x1, short y1, short x2, short y2 ) { UI_GADGET * gadget; gadget = (UI_GADGET *) d_malloc(sizeof(UI_GADGET)); if (gadget==NULL) Error("Could not create gadget: Out of memory"); if (dlg->gadget == NULL ) { dlg->gadget = gadget; gadget->prev = gadget; gadget->next = gadget; } else { dlg->gadget->prev->next = gadget; gadget->next = dlg->gadget; gadget->prev = dlg->gadget->prev; dlg->gadget->prev = gadget; } gadget->when_tab = NULL; gadget->when_btab = NULL; gadget->when_up = NULL; gadget->when_down = NULL; gadget->when_left = NULL; gadget->when_right = NULL; gadget->kind = kind; gadget->status = 1; gadget->oldstatus = 0; if ( x1==0 && x2==0 && y1==0 && y2== 0 ) gadget->canvas = NULL; else gadget->canvas = gr_create_sub_canvas( window_get_canvas(ui_dialog_get_window( dlg )), x1, y1, x2-x1+1, y2-y1+1 ); gadget->x1 = gadget->canvas->cv_bitmap.bm_x; gadget->y1 = gadget->canvas->cv_bitmap.bm_y; gadget->x2 = gadget->canvas->cv_bitmap.bm_x+x2-x1+1; gadget->y2 = gadget->canvas->cv_bitmap.bm_y+y2-y1+1; gadget->parent = NULL; gadget->hotkey = -1; return gadget; } void ui_gadget_delete_all( UI_DIALOG * dlg ) { UI_GADGET * tmp; while( dlg->gadget != NULL ) { tmp = dlg->gadget; if (tmp->next == tmp ) { dlg->gadget = NULL; } else { tmp->next->prev = tmp->prev; tmp->prev->next = tmp->next; dlg->gadget = tmp->next; } if (tmp->canvas) gr_free_sub_canvas( tmp->canvas ); if (tmp->kind == 1 ) // Button { UI_GADGET_BUTTON * but1 = (UI_GADGET_BUTTON *)tmp; if (but1->text) d_free( but1->text ); } if (tmp->kind == 4 ) // Radio { UI_GADGET_RADIO * but1 = (UI_GADGET_RADIO *)tmp; if (but1->text) d_free( but1->text ); } if (tmp->kind == 6 ) // Inputbox { UI_GADGET_INPUTBOX * but1 = (UI_GADGET_INPUTBOX *)tmp; d_free( but1->text ); } if (tmp->kind == 5 ) // Checkbox { UI_GADGET_CHECKBOX * but1 = (UI_GADGET_CHECKBOX *)tmp; d_free( but1->text ); } if (tmp->kind == 9 ) // Icon { UI_GADGET_ICON * but1 = (UI_GADGET_ICON *)tmp; d_free( but1->text ); } d_free( tmp ); } } #if 0 int is_under_another_window( UI_DIALOG * dlg, UI_GADGET * gadget ) { UI_DIALOG * temp; temp = dlg->next; while( temp != NULL ) { if ( ( gadget->x1 > temp->x) && ( gadget->x1 < (temp->x+temp->width) ) && ( gadget->y1 > temp->y) && ( gadget->y1 < (temp->y+temp->height) ) ) { //gadget->status =1; return 1; } if ( ( gadget->x2 > temp->x) && ( gadget->x2 < (temp->x+temp->width) ) && ( gadget->y2 > temp->y) && ( gadget->y2 < (temp->y+temp->height) ) ) { //gadget->status =1; return 1; } temp = temp->next; } return 0; } #endif int ui_mouse_on_gadget( UI_GADGET * gadget ) { int x, y, z; mouse_get_pos(&x, &y, &z); if ((x >= gadget->x1) && (x <= gadget->x2-1) && (y >= gadget->y1) && (y <= gadget->y2-1) ) { #if 0 // check is no longer required - if it is under another window, that dialog's handler would have returned 1 if (is_under_another_window(dlg, gadget)) return 0; #endif return 1; } else return 0; } int ui_gadget_do(UI_DIALOG *dlg, UI_GADGET *g, d_event *event) { switch( g->kind ) { case 1: return ui_button_do(dlg, (UI_GADGET_BUTTON *)g, event); break; case 2: return ui_listbox_do(dlg, (UI_GADGET_LISTBOX *)g, event); break; case 3: return ui_scrollbar_do(dlg, (UI_GADGET_SCROLLBAR *)g, event); break; case 4: return ui_radio_do(dlg, (UI_GADGET_RADIO *)g, event); break; case 5: return ui_checkbox_do(dlg, (UI_GADGET_CHECKBOX *)g, event); break; case 6: return ui_inputbox_do(dlg, (UI_GADGET_INPUTBOX *)g, event); break; case 7: return ui_userbox_do(dlg, (UI_GADGET_USERBOX *)g, event); break; case 8: return ui_keytrap_do((UI_GADGET_KEYTRAP *)g, event); break; case 9: return ui_icon_do(dlg, (UI_GADGET_ICON *)g, event); break; } return 0; } int ui_gadget_send_event(UI_DIALOG *dlg, event_type type, UI_GADGET *gadget) { event_gadget event; event.type = type; event.gadget = gadget; if (gadget->parent) return ui_gadget_do(dlg, gadget->parent, (d_event *) &event); return window_send_event(ui_dialog_get_window(dlg), (d_event *) &event); } UI_GADGET *ui_event_get_gadget(d_event *event) { Assert(event->type >= EVENT_UI_GADGET_PRESSED); // Any UI event return ((event_gadget *) event)->gadget; } int ui_dialog_do_gadgets(UI_DIALOG * dlg, d_event *event) { int keypress = 0; UI_GADGET * tmp, * tmp1; window *wind; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); tmp = dlg->gadget; if (tmp == NULL) return 0; if (selected_gadget==NULL) selected_gadget = tmp; tmp1 = dlg->keyboard_focus_gadget; do { if (ui_mouse_on_gadget(tmp) && B1_JUST_PRESSED ) { selected_gadget = tmp; if (tmp->parent!=NULL) { while (tmp->parent != NULL ) tmp = tmp->parent; dlg->keyboard_focus_gadget = tmp; break; } else { dlg->keyboard_focus_gadget = tmp; break; } } if ( tmp->hotkey == keypress ) { dlg->keyboard_focus_gadget = tmp; break; } tmp = tmp->next; } while( tmp != dlg->gadget ); if (dlg->keyboard_focus_gadget != NULL) { switch (keypress ) { case (KEY_TAB): if ( dlg->keyboard_focus_gadget->when_tab != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_tab; break; case (KEY_TAB+KEY_SHIFTED): if ( dlg->keyboard_focus_gadget->when_btab != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_btab; break; case (KEY_UP): if ( dlg->keyboard_focus_gadget->when_up != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_up; break; case (KEY_DOWN): if ( dlg->keyboard_focus_gadget->when_down != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_down; break; case (KEY_LEFT): if ( dlg->keyboard_focus_gadget->when_left != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_left; break; case (KEY_RIGHT): if ( dlg->keyboard_focus_gadget->when_right != NULL ) dlg->keyboard_focus_gadget = dlg->keyboard_focus_gadget->when_right; break; } } if (dlg->keyboard_focus_gadget != tmp1) { if (dlg->keyboard_focus_gadget != NULL ) dlg->keyboard_focus_gadget->status = 1; if (tmp1 != NULL ) tmp1->status = 1; rval = 1; if (keypress) return rval; } tmp = dlg->gadget; wind = ui_dialog_get_window(dlg); do { // If it is under another dialog, that dialog's handler would have returned 1 for mouse events. // Key events are handled in a priority depending on the window ordering. //if (!is_under_another_window( dlg, tmp )) rval = ui_gadget_do(dlg, tmp, event); if (!window_exists(wind)) break; tmp = tmp->next; } while(/*!rval &&*/ tmp != dlg->gadget); // have to look for pesky scrollbars in case an arrow button or arrow key are held down return rval; } UI_GADGET * ui_gadget_get_next( UI_GADGET * gadget ) { UI_GADGET * tmp; tmp = gadget->next; while( tmp != gadget && (tmp->parent!=NULL) ) tmp = tmp->next; return tmp; } UI_GADGET * ui_gadget_get_prev( UI_GADGET * gadget ) { UI_GADGET * tmp; tmp = gadget->prev; while( tmp != gadget && (tmp->parent!=NULL) ) tmp = tmp->prev; return tmp; } void ui_gadget_calc_keys( UI_DIALOG * dlg) { UI_GADGET * tmp; tmp = dlg->gadget; if (tmp==NULL) return; do { tmp->when_tab = ui_gadget_get_next(tmp); tmp->when_btab = ui_gadget_get_prev(tmp); tmp = tmp->next; } while( tmp != dlg->gadget ); } dxx-rebirth-0.58.1-d1x/ui/icon.c000066400000000000000000000101641217717257200162650ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/ui/icon.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:11 $ * * An icon class. * * $Log: icon.c,v $ * Revision 1.1.1.1 2006/03/17 19:39:11 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:14:27 donut * Import of d1x 1.37 source. * * Revision 1.2 1994/11/18 23:07:33 john * Changed a bunch of shorts to ints. * * Revision 1.1 1993/12/07 12:30:23 john * Initial revision * * */ #include #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #define Middle(x) ((2*(x)+1)/4) void ui_draw_box_in1( short x1, short y1, short x2, short y2 ) { gr_setcolor( CWHITE ); gr_urect( x1+1, y1+1, x2-1, y2-1 ); ui_draw_shad( x1+0, y1+0, x2-0, y2-0, CGREY, CBRIGHT ); } void ui_draw_icon( UI_GADGET_ICON * icon ) { int height, width, avg; int x, y; #if 0 //ndef OGL if ((icon->status==1) || (icon->position != icon->oldposition)) #endif { icon->status = 0; gr_set_current_canvas( icon->canvas ); gr_get_string_size(icon->text, &width, &height, &avg ); x = ((icon->width-1)/2)-((width-1)/2); y = ((icon->height-1)/2)-((height-1)/2); if (icon->position==1 ) { // Draw pressed ui_draw_box_in( 0, 0, icon->width, icon->height ); x += 2; y += 2; } else if (icon->flag) { // Draw part out ui_draw_box_in1( 0, 0, icon->width, icon->height ); x += 1; y += 1; } else { // Draw released! ui_draw_box_out( 0, 0, icon->width, icon->height ); } gr_set_fontcolor( CBLACK, -1 ); gr_ustring( x, y, icon->text ); } } UI_GADGET_ICON * ui_add_gadget_icon( UI_DIALOG * dlg, char * text, short x, short y, short w, short h, int k,int (*f)(void) ) { UI_GADGET_ICON * icon; icon = (UI_GADGET_ICON *)ui_gadget_add( dlg, 9, x, y, x+w-1, y+h-1 ); icon->width = w; icon->height = h; MALLOC( icon->text, char, strlen( text )+2);//Hack by KRB strcpy( icon->text, text ); icon->trap_key = k; icon->user_function = f; icon->oldposition = 0; icon->position = 0; icon->pressed = 0; icon->canvas->cv_font = ui_small_font; // Call twice to get original; if (f) { icon->flag = (sbyte)f(); icon->flag = (sbyte)f(); } else { icon->flag = 0; } return icon; } int ui_icon_do( UI_DIALOG *dlg, UI_GADGET_ICON * icon, d_event *event ) { int rval = 0; icon->oldposition = icon->position; icon->pressed = 0; if (event->type == EVENT_MOUSE_BUTTON_DOWN || event->type == EVENT_MOUSE_BUTTON_UP) { int OnMe; OnMe = ui_mouse_on_gadget( (UI_GADGET *)icon ); if (B1_JUST_PRESSED && OnMe) { icon->position = 1; rval = 1; } else if (B1_JUST_RELEASED) { if ((icon->position == 1) && OnMe) icon->pressed = 1; icon->position = 0; } } if (event->type == EVENT_KEY_COMMAND) { int key; key = event_key_get(event); if (key == icon->trap_key) { icon->position = 1; rval = 1; } } else if (event->type == EVENT_KEY_RELEASE) { int key; key = event_key_get(event); icon->position = 0; if (key == icon->trap_key) icon->pressed = 1; } if (icon->pressed == 1) { icon->status = 1; icon->flag = (sbyte)icon->user_function(); ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)icon); rval = 1; } if (event->type == EVENT_WINDOW_DRAW) ui_draw_icon( icon ); return rval; } dxx-rebirth-0.58.1-d1x/ui/inputbox.c000066400000000000000000000111541217717257200172050ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "key.h" #include "mouse.h" // insert character c into string s at position p. void strcins(char *s, int p, char c) { int n; for (n=strlen(s)-p; n>=0; n-- ) *(s+p+n+1) = *(s+p+n); // Move everything over *(s+p) = c; // then insert the character } // delete n character from string s starting at position p void strndel(char *s, int p, int n) { for (; (*(s+p) = *(s+p+n)) != '\0'; s++ ) *(s+p+n) = '\0'; // Delete and zero fill } void ui_draw_inputbox( UI_DIALOG *dlg, UI_GADGET_INPUTBOX * inputbox ) { int w, h, aw; #if 0 //ndef OGL if ((inputbox->status==1) || (inputbox->position != inputbox->oldposition)) #endif { gr_set_current_canvas( inputbox->canvas ); gr_setcolor( CBLACK ); gr_rect( 0, 0, inputbox->width-1, inputbox->height-1 ); gr_get_string_size(inputbox->text, &w, &h, &aw ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)inputbox) { if (inputbox->first_time) { gr_set_fontcolor( CBLACK, -1 ); gr_setcolor( CRED ); gr_rect(2, 2, 2 + w, 2 + h); } else gr_set_fontcolor( CRED, -1 ); } else gr_set_fontcolor( CWHITE, -1 ); inputbox->status = 0; gr_string( 2, 2, inputbox->text ); //gr_setcolor( CBLACK ); //gr_rect( 2+w, 0, inputbox->width-1, inputbox->height-1 ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)inputbox && !inputbox->first_time ) { gr_setcolor(CRED); Vline( 2,inputbox->height-3, 2+w+1 ); Vline( 2,inputbox->height-3, 2+w+2 ); } } } UI_GADGET_INPUTBOX * ui_add_gadget_inputbox( UI_DIALOG * dlg, short x, short y, short length, short slength, char * text ) { int h, w, aw; UI_GADGET_INPUTBOX * inputbox; gr_get_string_size( NULL, &w, &h, &aw ); inputbox = (UI_GADGET_INPUTBOX *)ui_gadget_add( dlg, 6, x, y, x+aw*slength-1, y+h-1+4 ); inputbox->text = d_malloc(length + 1); strncpy( inputbox->text, text, length ); inputbox->position = strlen(inputbox->text); inputbox->oldposition = inputbox->position; inputbox->width = aw*slength; inputbox->height = h+4; inputbox->length = length; inputbox->slength = slength; inputbox->pressed = 0; inputbox->first_time = 1; return inputbox; } int ui_inputbox_do( UI_DIALOG *dlg, UI_GADGET_INPUTBOX * inputbox, d_event *event ) { unsigned char ascii; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); inputbox->oldposition = inputbox->position; inputbox->pressed=0; if (dlg->keyboard_focus_gadget==(UI_GADGET *)inputbox) { switch( keypress ) { case 0: break; case (KEY_LEFT): case (KEY_BACKSP): if (inputbox->position > 0) inputbox->position--; inputbox->text[inputbox->position] = 0; inputbox->status = 1; if (inputbox->first_time) inputbox->first_time = 0; rval = 1; break; case (KEY_ENTER): inputbox->pressed=1; inputbox->status = 1; if (inputbox->first_time) inputbox->first_time = 0; rval = 1; break; default: ascii = key_ascii(); if ((ascii < 255 ) && (inputbox->position < inputbox->length-2)) { if (inputbox->first_time) { inputbox->first_time = 0; inputbox->position = 0; } inputbox->text[inputbox->position++] = ascii; inputbox->text[inputbox->position] = 0; rval = 1; } inputbox->status = 1; break; } } else { inputbox->first_time = 1; } if (inputbox->pressed) { ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)inputbox); rval = 1; } if (event->type == EVENT_WINDOW_DRAW) ui_draw_inputbox( dlg, inputbox ); return rval; } void ui_inputbox_set_text(UI_GADGET_INPUTBOX *inputbox, char *text) { strncpy(inputbox->text, text, inputbox->length + 1); inputbox->position = strlen(text); inputbox->oldposition = inputbox->position; inputbox->status = 1; // redraw inputbox->first_time = 1; // select all } dxx-rebirth-0.58.1-d1x/ui/keypad.c000066400000000000000000000405561217717257200166220ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include #include "physfsx.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "key.h" #include "ui.h" #include "u_mem.h" #include "func.h" #include "dxxerror.h" #define MAX_NUM_PADS 20 static UI_GADGET_BUTTON * Pad[17]; static UI_KEYPAD * KeyPad[MAX_NUM_PADS]; static int active_pad; static int desc_x, desc_y; static int HotKey[17]; static int HotKey1[17]; #define REMOVE_EOL(s) (*(strstr( (s), "\n" ))='\0') int ui_pad_get_current() { return active_pad; } void ui_pad_init() { int i; for (i=0; i< MAX_NUM_PADS; i++ ) KeyPad[i] = NULL; active_pad = -1; } void ui_pad_close() { int i, j; for (i=0; i< MAX_NUM_PADS; i++ ) if (KeyPad[i]) { for (j=0; j<17; j++ ) d_free(KeyPad[i]->buttontext[j]); d_free( KeyPad[i] ); KeyPad[i] = NULL; } } void LineParse( int n, char * dest, char * source ) { int i = 0, j=0, cn = 0; // Go to the n'th line while (cn < n ) if ((unsigned char) source[i++] == 179) cn++; // Read up until the next comma while ((unsigned char) source[i] != 179) { dest[j] = source[i++]; j++; } // Null-terminate dest[j++] = 0; } void ui_pad_activate( UI_DIALOG * dlg, int x, int y ) { int w,h,row,col, n; int bh, bw; bw = 56; bh = 30; x += 5; y += 20; desc_x = x+2; desc_y = y-17; n=0; row = 0; col = 0; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=1; row = 0; col = 1; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=2; row = 0; col = 2; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=3; row = 0; col = 3; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=4; row = 1; col = 0; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=5; row = 1; col = 1; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=6; row = 1; col = 2; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=7; row = 1; col = 3; w = 1; h = 2; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=8; row = 2; col = 0; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=9; row = 2; col = 1; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=10; row = 2; col = 2; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=11; row = 3; col = 0; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=12; row = 3; col = 1; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=13; row = 3; col = 2; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=14; row = 3; col = 3; w = 1; h = 2; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=15; row = 4; col = 0; w = 2; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; n=16; row = 4; col = 2; w = 1; h = 1; Pad[n] = ui_add_gadget_button( dlg, x+(bw*col), y+(bh*row), bw*w, bh*h, NULL, NULL ); Pad[n]->canvas->cv_font = ui_small_font; HotKey[0] = KEY_CTRLED + KEY_NUMLOCK; HotKey[1] = KEY_CTRLED + KEY_PADDIVIDE; HotKey[2] = KEY_CTRLED + KEY_PADMULTIPLY; HotKey[3] = KEY_CTRLED + KEY_PADMINUS; HotKey[4] = KEY_CTRLED + KEY_PAD7; HotKey[5] = KEY_CTRLED + KEY_PAD8; HotKey[6] = KEY_CTRLED + KEY_PAD9; HotKey[7] = KEY_CTRLED + KEY_PADPLUS; HotKey[8] = KEY_CTRLED + KEY_PAD4; HotKey[9] = KEY_CTRLED + KEY_PAD5; HotKey[10] = KEY_CTRLED + KEY_PAD6; HotKey[11] = KEY_CTRLED + KEY_PAD1; HotKey[12] = KEY_CTRLED + KEY_PAD2; HotKey[13] = KEY_CTRLED + KEY_PAD3; HotKey[14] = KEY_CTRLED + KEY_PADENTER; HotKey[15] = KEY_CTRLED + KEY_PAD0; HotKey[16] = KEY_CTRLED + KEY_PADPERIOD; HotKey1[0] = KEY_SHIFTED + KEY_CTRLED + KEY_NUMLOCK; HotKey1[1] = KEY_SHIFTED + KEY_CTRLED + KEY_PADDIVIDE; HotKey1[2] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMULTIPLY; HotKey1[3] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMINUS; HotKey1[4] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD7; HotKey1[5] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD8; HotKey1[6] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD9; HotKey1[7] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPLUS; HotKey1[8] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD4; HotKey1[9] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD5; HotKey1[10] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD6; HotKey1[11] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD1; HotKey1[12] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD2; HotKey1[13] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD3; HotKey1[14] = KEY_SHIFTED + KEY_CTRLED + KEY_PADENTER; HotKey1[15] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD0; HotKey1[16] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPERIOD; active_pad = -1; } void ui_pad_deactivate() { int i; for (i=0; i<17; i++ ) { Pad[i]->text = NULL; } } void ui_pad_draw(UI_DIALOG *dlg, int x, int y) { int bh, bw; bw = 56; bh = 30; ui_dialog_set_current_canvas( dlg ); ui_draw_box_in( x, y, x+(bw*4)+10 + 200, y+(bh*5)+45 ); gr_set_current_canvas( NULL ); gr_setcolor( CWHITE ); gr_urect( desc_x, desc_y, desc_x+ 56*4-1, desc_y+15 ); gr_set_fontcolor( CBLACK, CWHITE ); gr_ustring( desc_x, desc_y, KeyPad[active_pad]->description ); } static void ui_pad_set_active( int n ) { int np; char * name; int i, j; for (i=0; i<17; i++ ) { Pad[i]->text = KeyPad[n]->buttontext[i]; Pad[i]->status = 1; Pad[i]->user_function = NULL; Pad[i]->dim_if_no_function = 1; Pad[i]->hotkey = -1; for (j=0; j< KeyPad[n]->numkeys; j++ ) { if (HotKey[i] == KeyPad[n]->keycode[j] ) { Pad[i]->hotkey = HotKey[i]; Pad[i]->user_function = func_nget( KeyPad[n]->function_number[j], &np, &name ); } if (HotKey1[i] == KeyPad[n]->keycode[j] ) { Pad[i]->hotkey1 = HotKey1[i]; Pad[i]->user_function1 = func_nget( KeyPad[n]->function_number[j], &np, &name ); } } } active_pad = n; } void ui_pad_goto(int n) { if ( KeyPad[n] != NULL ) ui_pad_set_active(n); } void ui_pad_goto_next() { int i, si; i = active_pad + 1; si = i; while( KeyPad[i]==NULL ) { i++; if (i >= MAX_NUM_PADS) i = 0; if (i == si ) break; } ui_pad_set_active(i); } void ui_pad_goto_prev() { int i; if (active_pad == -1 ) active_pad = MAX_NUM_PADS; i = active_pad - 1; if (i<0) i= MAX_NUM_PADS - 1; while( KeyPad[i]==NULL ) { i--; if (i < 0) i = MAX_NUM_PADS-1; if (i == active_pad ) break; } ui_pad_set_active(i); } void ui_pad_read( int n, char * filename ) { char * ptr; char buffer[100]; char text[100]; char line_buffer[200]; PHYSFS_file * infile; int linenumber = 0; int i; int keycode, functionnumber; infile = PHYSFSX_openReadBuffered( filename ); if (!infile) { Warning( "Couldn't find %s\n", filename ); return; } MALLOC( KeyPad[n], UI_KEYPAD, 1 ); for (i=0; i < 17; i++ ) { MALLOC( KeyPad[n]->buttontext[i], char, 100 ); } KeyPad[n]->numkeys = 0; for (i=0; i<100; i++ ) { KeyPad[n]->keycode[i] = -1; KeyPad[n]->function_number[i] = 0; } while ( linenumber < 22) { PHYSFSX_fgets( buffer, 100, infile ); switch( linenumber+1 ) { case 1: strncpy( KeyPad[n]->description, buffer, 100 ); break; //===================== ROW 0 ============================== case 3: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[0], "%s\n", text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[1], "%s\n", text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[2], "%s\n", text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[3], "%s\n", text ); break; case 4: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[0], "%s%s\n", KeyPad[n]->buttontext[0],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[1], "%s%s\n", KeyPad[n]->buttontext[1],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[2], "%s%s\n", KeyPad[n]->buttontext[2],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[3], "%s%s\n", KeyPad[n]->buttontext[3],text ); break; case 5: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[0], "%s%s", KeyPad[n]->buttontext[0],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[1], "%s%s", KeyPad[n]->buttontext[1],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[2], "%s%s", KeyPad[n]->buttontext[2],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[3], "%s%s", KeyPad[n]->buttontext[3],text ); break; //===================== ROW 1 ============================== case 7: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[4], "%s\n", text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[5], "%s\n", text ); LineParse( 3, text, buffer); sprintf( KeyPad[n]->buttontext[6], "%s\n", text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s\n", text ); break; case 8: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[4], "%s%s\n", KeyPad[n]->buttontext[4],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[5], "%s%s\n", KeyPad[n]->buttontext[5],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[6], "%s%s\n", KeyPad[n]->buttontext[6],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s%s\n", KeyPad[n]->buttontext[7],text ); break; case 9: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[4], "%s%s", KeyPad[n]->buttontext[4],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[5], "%s%s", KeyPad[n]->buttontext[5],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[6], "%s%s", KeyPad[n]->buttontext[6],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s%s\n", KeyPad[n]->buttontext[7],text ); break; case 10: ptr = strrchr( buffer, (char) 179 ); *ptr = 0; ptr = strrchr( buffer, (char) 180 ); ptr++; sprintf( KeyPad[n]->buttontext[7], "%s%s\n", KeyPad[n]->buttontext[7],ptr ); break; //======================= ROW 2 ============================== case 11: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[8], "%s\n", text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[9], "%s\n", text ); LineParse( 3, text, buffer); sprintf( KeyPad[n]->buttontext[10], "%s\n", text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s%s\n", KeyPad[n]->buttontext[7],text ); break; case 12: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[8], "%s%s\n", KeyPad[n]->buttontext[8],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[9], "%s%s\n", KeyPad[n]->buttontext[9],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[10], "%s%s\n", KeyPad[n]->buttontext[10],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s%s\n", KeyPad[n]->buttontext[7],text ); break; case 13: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[8], "%s%s", KeyPad[n]->buttontext[8],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[9], "%s%s", KeyPad[n]->buttontext[9],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[10], "%s%s", KeyPad[n]->buttontext[10],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[7], "%s%s", KeyPad[n]->buttontext[7],text ); break; // ====================== ROW 3 ========================= case 15: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[11], "%s\n", text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[12], "%s\n", text ); LineParse( 3, text, buffer); sprintf( KeyPad[n]->buttontext[13], "%s\n", text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s\n", text ); break; case 16: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[11], "%s%s\n", KeyPad[n]->buttontext[11],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[12], "%s%s\n", KeyPad[n]->buttontext[12],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[13], "%s%s\n", KeyPad[n]->buttontext[13],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s%s\n", KeyPad[n]->buttontext[14],text ); break; case 17: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[11], "%s%s", KeyPad[n]->buttontext[11],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[12], "%s%s", KeyPad[n]->buttontext[12],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[13], "%s%s", KeyPad[n]->buttontext[13],text ); LineParse( 4, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s%s\n", KeyPad[n]->buttontext[14],text ); break; case 18: ptr = strrchr( buffer, (char) 179 ); *ptr = 0; ptr = strrchr( buffer, (char) 180 ); ptr++; sprintf( KeyPad[n]->buttontext[14], "%s%s\n", KeyPad[n]->buttontext[14], ptr ); break; //======================= ROW 4 ========================= case 19: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[15], "%s\n", text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[16], "%s\n", text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s%s\n", KeyPad[n]->buttontext[14],text ); break; case 20: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[15], "%s%s\n", KeyPad[n]->buttontext[15],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[16], "%s%s\n", KeyPad[n]->buttontext[16],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s%s\n", KeyPad[n]->buttontext[14],text ); break; case 21: LineParse( 1, text, buffer ); sprintf( KeyPad[n]->buttontext[15], "%s%s", KeyPad[n]->buttontext[15],text ); LineParse( 2, text, buffer ); sprintf( KeyPad[n]->buttontext[16], "%s%s", KeyPad[n]->buttontext[16],text ); LineParse( 3, text, buffer ); sprintf( KeyPad[n]->buttontext[14], "%s%s", KeyPad[n]->buttontext[14],text ); break; } linenumber++; } // Get the keycodes... while (PHYSFSX_fgets(line_buffer, 200, infile)) { sscanf(line_buffer, " %s %s ", text, buffer); keycode = DecodeKeyText(text); functionnumber = func_get_index(buffer); if (functionnumber==-1) { Error( "Unknown function, %s, in %s\n", buffer, filename ); } else if (keycode==-1) { Error( "Unknown keystroke, %s, in %s\n", text, filename ); //ui_messagebox( -2, -2, 1, buffer, "Ok" ); } else { KeyPad[n]->keycode[KeyPad[n]->numkeys] = keycode; KeyPad[n]->function_number[KeyPad[n]->numkeys] = functionnumber; KeyPad[n]->numkeys++; } } PHYSFS_close(infile); } dxx-rebirth-0.58.1-d1x/ui/keypress.c000066400000000000000000000102551217717257200172030ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include #include "fix.h" #include "pstypes.h" #include "gr.h" #include "event.h" #include "ui.h" #include "key.h" #include "window.h" char * KeyDesc[256] = { \ "","{Esc}","{1}","{2}","{3}","{4}","{5}","{6}","{7}","{8}","{9}","{0}","{-}", \ "{=}","{Backspace}","{Tab}","{Q}","{W}","{E}","{R}","{T}","{Y}","{U}","{I}","{O}", \ "{P}","{[}","{]}","{Enter}","{LeftCtrl}","{A}","{S}","{D}","{F}", \ "{G}","{H}","{J}","{K}","{L}","{;}","{'}","{`}", \ "{RightShift}","{\\}","{Z}","{X}","{C}","{V}","{B}","{N}","{M}","{,}", \ "{.}","{/}","{LeftShift}","{Pad*}","{LeftAlt}","{Spacebar}", \ "{CapsLock}","{F1}","{F2}","{F3}","{F4}","{F5}","{F6}","{F7}","{F8}","{F9}", \ "{F10}","{NumLock}","{ScrollLock}","{Pad7}","{Pad8}","{Pad9}","{Pad-}", \ "{Pad4}","{Pad5}","{Pad6}","{Pad+}","{Pad1}","{Pad2}","{Pad3}","{Pad0}", \ "{Pad.}","","","","{F11}","{F12}","","","","","","","","","", \ "","","","","","","","","","","","","","","","","","","","", \ "","","","","","","","","","","","","","","","","","","","", \ "","","","","","","","","","","","","","","","","","", \ "{PadEnter}","{RightCtrl}","","","","","","","","","","","","","", \ "","","","","","","","","","","{Pad/}","","","{RightAlt}","", \ "","","","","","","","","","","","","","{Home}","{Up}","{PageUp}", \ "","{Left}","","{Right}","","{End}","{Down}","{PageDown}","{Insert}", \ "{Delete}","","","","","","","","","","","","","","","","","", \ "","","","","","","","","","","","","","","","","","","","", \ "","","","","","","" }; void GetKeyDescription( char * text, int keypress ) { char Ctrl[10]; char Alt[10]; char Shift[10]; if (keypress & KEY_CTRLED) strcpy( Ctrl, "{Ctrl}"); else strcpy( Ctrl, ""); if (keypress & KEY_ALTED) strcpy( Alt, "{Alt}"); else strcpy( Alt, ""); if (keypress & KEY_SHIFTED) strcpy( Shift, "{Shift}"); else strcpy( Shift, ""); sprintf( text, "%s%s%s%s", Ctrl, Alt, Shift, KeyDesc[keypress & 255 ] ); } int DecodeKeyText( char * text ) { int i, code = 0; if (strstr(text, "{Ctrl}") ) code |= KEY_CTRLED; if (strstr(text, "{Alt}") ) code |= KEY_ALTED; if (strstr(text, "{Shift}") ) code |= KEY_SHIFTED; for (i=0; i<256; i++ ) { if ( strlen(KeyDesc[i])>0 && strstr(text, KeyDesc[i]) ) { code |= i; return code; } } return -1; } typedef struct key_dialog { UI_GADGET_BUTTON *DoneButton; char text[100]; } key_dialog; static int key_dialog_handler(UI_DIALOG *dlg, d_event *event, key_dialog *k) { int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); else if (event->type == EVENT_UI_DIALOG_DRAW) { ui_dprintf_at( dlg, 10, 100, "%s ", k->text ); return 1; } if (keypress > 0) { GetKeyDescription( k->text, keypress ); rval = 1; } if (GADGET_PRESSED(k->DoneButton)) { ui_close_dialog(dlg); rval = 1; } return rval; } int GetKeyCode(char * text) { UI_DIALOG * dlg; window *wind; key_dialog k; text = text; dlg = ui_create_dialog( 200, 200, 400, 200, DF_DIALOG | DF_MODAL, (int (*)(UI_DIALOG *, d_event *, void *))key_dialog_handler, &k ); k.DoneButton = ui_add_gadget_button( dlg, 170, 165, 60, 25, "Ok", NULL ); strcpy(k.text, ""); ui_gadget_calc_keys(dlg); //key_flush(); dlg->keyboard_focus_gadget = (UI_GADGET *)k.DoneButton; wind = ui_dialog_get_window(dlg); while (window_exists(wind)) event_process(); return 0; } dxx-rebirth-0.58.1-d1x/ui/keytrap.c000066400000000000000000000027531217717257200170210ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "key.h" UI_GADGET_KEYTRAP * ui_add_gadget_keytrap( UI_DIALOG * dlg, int key_to_trap, int (*function_to_call)(void) ) { UI_GADGET_KEYTRAP * keytrap; keytrap = (UI_GADGET_KEYTRAP *)ui_gadget_add( dlg, 8, 0, 0, 0, 0 ); keytrap->parent = (UI_GADGET *)keytrap; keytrap->trap_key = key_to_trap; keytrap->user_function = function_to_call; return keytrap; } int ui_keytrap_do( UI_GADGET_KEYTRAP * keytrap, d_event *event ) { int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); if ( keypress == keytrap->trap_key ) { keytrap->user_function(); rval = 1; } return rval; } dxx-rebirth-0.58.1-d1x/ui/listbox.c000066400000000000000000000252071217717257200170250ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "timer.h" void gr_draw_sunken_border( short x1, short y1, short x2, short y2 ); void ui_draw_listbox( UI_DIALOG *dlg, UI_GADGET_LISTBOX * listbox ) { int i, x, y, stop; int w, h, aw; //if (listbox->current_item<0) // listbox->current_item=0; //if (listbox->current_item>=listbox->num_items) // listbox->current_item = listbox->num_items-1; //if (listbox->first_item<0) // listbox->first_item=0; //if (listbox->first_item>(listbox->num_items-listbox->num_items_displayed)) // listbox->first_item=(listbox->num_items-listbox->num_items_displayed); #if 0 //ndef OGL if ((listbox->status!=1) && !listbox->moved ) return; #endif gr_set_current_canvas( listbox->canvas ); w = listbox->width; h = listbox->height; gr_setcolor(CBLACK); gr_rect( 0, 0, w-1, h-1); gr_draw_sunken_border( -2, -2, w+listbox->scrollbar->width+4, h+1); stop = listbox->first_item+listbox->num_items_displayed; if (stop>listbox->num_items) stop = listbox->num_items; listbox->status = 0; x = y = 0; for (i= listbox->first_item; i< stop; i++ ) { if (i==listbox->current_item) gr_setcolor( CGREY ); else gr_setcolor( CBLACK ); gr_rect(x, y, listbox->width - 1, y + h - 1); if (i !=listbox->current_item) { if ((listbox->current_item == -1) && (dlg->keyboard_focus_gadget == (UI_GADGET *)listbox) && (i == listbox->first_item) ) gr_set_fontcolor( CRED, -1 ); else gr_set_fontcolor( CWHITE, -1 ); } else { if (dlg->keyboard_focus_gadget == (UI_GADGET *)listbox) gr_set_fontcolor( CRED, -1 ); else gr_set_fontcolor( CBLACK, -1 ); } gr_string(x + 2, y, listbox->list[i]); gr_get_string_size(listbox->list[i], &w, &h, &aw); y += h; } if (stop < listbox->num_items_displayed-1 ) { gr_setcolor(CBLACK); gr_rect( x, y, listbox->width-1, listbox->height-1 ); } //gr_ubox( -1, -1, listbox->width, listbox->height); } void gr_draw_sunken_border( short x1, short y1, short x2, short y2 ) { gr_setcolor( CGREY ); Hline( x1-1, x2+1, y1-1); Vline( y1-1, y2+1, x1-1); gr_setcolor( CBRIGHT ); Hline( x1-1, x2+1, y2+1); Vline( y1, y2+1, x2+1); } UI_GADGET_LISTBOX * ui_add_gadget_listbox(UI_DIALOG *dlg, short x, short y, short w, short h, short numitems, char **list) { int tw, th, taw, i; UI_GADGET_LISTBOX * listbox; gr_get_string_size("*", &tw, &th, &taw ); i = h / th; h = i * th; listbox = (UI_GADGET_LISTBOX *)ui_gadget_add( dlg, 2, x, y, x+w-1, y+h-1 ); listbox->list = list; listbox->width = w; listbox->height = h; listbox->num_items = numitems; listbox->num_items_displayed = i; listbox->first_item = 0; listbox->current_item = -1; listbox->last_scrolled = 0; listbox->textheight = th; listbox->dragging = 0; listbox->selected_item = -1; listbox->moved = 1; listbox->scrollbar = ui_add_gadget_scrollbar( dlg, x+w+3, y, 0, h, 0, numitems-i, 0, i ); listbox->scrollbar->parent = (UI_GADGET *)listbox; return listbox; } int ui_listbox_do( UI_DIALOG *dlg, UI_GADGET_LISTBOX * listbox, d_event *event ) { int mitem, oldfakepos, kf; int keypress = 0; int rval = 0; if (event->type == EVENT_WINDOW_DRAW) { ui_draw_listbox( dlg, listbox ); return 0; } if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); listbox->selected_item = -1; listbox->moved = 0; if (listbox->num_items < 1 ) { listbox->current_item = -1; listbox->first_item = 0; listbox->old_current_item = listbox->current_item; listbox->old_first_item = listbox->first_item; //ui_draw_listbox( dlg, listbox ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)listbox) { dlg->keyboard_focus_gadget = ui_gadget_get_next((UI_GADGET *)listbox); } return rval; } listbox->old_current_item = listbox->current_item; listbox->old_first_item = listbox->first_item; if (GADGET_PRESSED(listbox->scrollbar)) { listbox->moved = 1; listbox->first_item = listbox->scrollbar->position; if (listbox->current_itemfirst_item) listbox->current_item = listbox->first_item; if (listbox->current_item>(listbox->first_item+listbox->num_items_displayed-1)) listbox->current_item = listbox->first_item + listbox->num_items_displayed-1; } if (B1_JUST_RELEASED) listbox->dragging = 0; if (B1_JUST_PRESSED && ui_mouse_on_gadget( (UI_GADGET *)listbox )) { listbox->dragging = 1; rval = 1; } if ( dlg->keyboard_focus_gadget==(UI_GADGET *)listbox ) { if (keypress==KEY_ENTER) { listbox->selected_item = listbox->current_item; rval = 1; } kf = 0; switch(keypress) { case (KEY_UP): listbox->current_item--; kf = 1; break; case (KEY_DOWN): listbox->current_item++; kf = 1; break; case (KEY_HOME): listbox->current_item=0; kf = 1; break; case (KEY_END): listbox->current_item=listbox->num_items-1; kf = 1; break; case (KEY_PAGEUP): listbox->current_item -= listbox->num_items_displayed; kf = 1; break; case (KEY_PAGEDOWN): listbox->current_item += listbox->num_items_displayed; kf = 1; break; } if (kf==1) { listbox->moved = 1; rval = 1; if (listbox->current_item<0) listbox->current_item=0; if (listbox->current_item>=listbox->num_items) listbox->current_item = listbox->num_items-1; if (listbox->current_itemfirst_item) listbox->first_item = listbox->current_item; if (listbox->current_item>=(listbox->first_item+listbox->num_items_displayed)) listbox->first_item = listbox->current_item-listbox->num_items_displayed+1; if (listbox->num_items <= listbox->num_items_displayed ) listbox->first_item = 0; else { oldfakepos = listbox->scrollbar->position; listbox->scrollbar->position = listbox->first_item; listbox->scrollbar->fake_position = listbox->scrollbar->position-listbox->scrollbar->start; listbox->scrollbar->fake_position *= listbox->scrollbar->height-listbox->scrollbar->fake_size; listbox->scrollbar->fake_position /= (listbox->scrollbar->stop-listbox->scrollbar->start); if (listbox->scrollbar->fake_position<0) { listbox->scrollbar->fake_position = 0; } if (listbox->scrollbar->fake_position > (listbox->scrollbar->height-listbox->scrollbar->fake_size)) { listbox->scrollbar->fake_position = (listbox->scrollbar->height-listbox->scrollbar->fake_size); } if (oldfakepos != listbox->scrollbar->position ) listbox->scrollbar->status = 1; } } } if (selected_gadget==(UI_GADGET *)listbox) { if (listbox->dragging) { int x, y, z; mouse_get_pos(&x, &y, &z); if (y < listbox->y1) mitem = -1; else mitem = (y - listbox->y1)/listbox->textheight; if ((mitem < 0) && (timer_query() > listbox->last_scrolled + 1)) { listbox->current_item--; listbox->last_scrolled = timer_query(); listbox->moved = 1; } if ((mitem >= listbox->num_items_displayed) && (timer_query() > listbox->last_scrolled + 1)) { listbox->current_item++; listbox->last_scrolled = timer_query(); listbox->moved = 1; } if ((mitem>=0) && (mitemnum_items_displayed)) { listbox->current_item = mitem+listbox->first_item; listbox->moved=1; } if (listbox->current_item <0 ) listbox->current_item = 0; if (listbox->current_item >= listbox->num_items ) listbox->current_item = listbox->num_items-1; if (listbox->current_itemfirst_item) listbox->first_item = listbox->current_item; if (listbox->current_item>=(listbox->first_item+listbox->num_items_displayed)) listbox->first_item = listbox->current_item-listbox->num_items_displayed+1; if (listbox->num_items <= listbox->num_items_displayed ) listbox->first_item = 0; else { oldfakepos = listbox->scrollbar->position; listbox->scrollbar->position = listbox->first_item; listbox->scrollbar->fake_position = listbox->scrollbar->position-listbox->scrollbar->start; listbox->scrollbar->fake_position *= listbox->scrollbar->height-listbox->scrollbar->fake_size; listbox->scrollbar->fake_position /= (listbox->scrollbar->stop-listbox->scrollbar->start); if (listbox->scrollbar->fake_position<0) { listbox->scrollbar->fake_position = 0; } if (listbox->scrollbar->fake_position > (listbox->scrollbar->height-listbox->scrollbar->fake_size)) { listbox->scrollbar->fake_position = (listbox->scrollbar->height-listbox->scrollbar->fake_size); } if (oldfakepos != listbox->scrollbar->position ) listbox->scrollbar->status = 1; } } if (B1_DOUBLE_CLICKED ) { listbox->selected_item = listbox->current_item; rval = 1; } } if (listbox->moved || (listbox->selected_item > 0)) { ui_gadget_send_event(dlg, (listbox->selected_item > 0) ? EVENT_UI_LISTBOX_SELECTED : EVENT_UI_LISTBOX_MOVED, (UI_GADGET *)listbox); rval = 1; } return rval; } void ui_listbox_change(UI_DIALOG *dlg, UI_GADGET_LISTBOX *listbox, short numitems, char **list) { int stop, start; UI_GADGET_SCROLLBAR * scrollbar; dlg = dlg; listbox->list = list; listbox->num_items = numitems; listbox->first_item = 0; listbox->current_item = -1; listbox->last_scrolled = timer_query(); listbox->dragging = 0; listbox->selected_item = -1; listbox->status = 1; listbox->first_item = 0; listbox->current_item = listbox->old_current_item = 0; listbox->moved = 0; scrollbar = listbox->scrollbar; start=0; stop= numitems - listbox->num_items_displayed; if (stop < start) stop = start; scrollbar->horz = 0; scrollbar->start = start; scrollbar->stop = stop; scrollbar->fake_length = scrollbar->height; scrollbar->fake_position = 0; if (stop!=start) scrollbar->fake_size = (listbox->num_items_displayed * scrollbar->height)/(stop-start+1+listbox->num_items_displayed); else scrollbar->fake_size = scrollbar->height; if (scrollbar->fake_size < 7) scrollbar->fake_size = 7; scrollbar->dragging = 0; scrollbar->moved=0; scrollbar->status=1; } dxx-rebirth-0.58.1-d1x/ui/menu.c000066400000000000000000000056641217717257200163120ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "event.h" #include "mouse.h" #include "ui.h" #define MENU_BORDER 2 #define MENU_VERT_SPACING 2 typedef struct menu { UI_GADGET_BUTTON ** button_g; char ** button; int *choice; int num_buttons; } menu; static int menu_handler(UI_DIALOG *dlg, d_event *event, menu *m) { int i; for (i=0; inum_buttons; i++ ) { if (GADGET_PRESSED(m->button_g[i])) { *(m->choice) = i+1; return 1; } } if ( (*(m->choice)==0) && B1_JUST_RELEASED ) { *(m->choice) = -1; return 1; } return 0; } int MenuX( int x, int y, int NumButtons, char * text[] ) { UI_DIALOG * dlg; menu *m; int button_width, button_height, width, height; int i; int w, h; int choice; MALLOC(m, menu, 1); m->num_buttons = NumButtons; m->button_g = (UI_GADGET_BUTTON **) d_malloc(sizeof(UI_GADGET_BUTTON *)*NumButtons); m->button = (char **) d_malloc(sizeof(char *)*NumButtons); m->choice = &choice; button_width = button_height = 0; for (i=0; ibutton[i] = text[i]; ui_get_button_size( m->button[i], &width, &height ); if ( width > button_width ) button_width = width; if ( height > button_height ) button_height = height; } width = button_width + 2*(MENU_BORDER+3); height = (button_height*NumButtons) + (MENU_VERT_SPACING*(NumButtons-1)) ; height += (MENU_BORDER+3) * 2; w = grd_curscreen->sc_w; h = grd_curscreen->sc_h; { int mx, my, mz; mouse_get_pos(&mx, &my, &mz); if ( x == -1 ) x = mx - width/2; if ( y == -1 ) y = my; } if (x < 0 ) { x = 0; } if ( (x+width-1) >= w ) { x = w - width; } if (y < 0 ) { y = 0; } if ( (y+height-1) >= h ) { y = h - height; } dlg = ui_create_dialog( x, y, width, height, DF_FILLED | DF_SAVE_BG | DF_MODAL, (int (*)(UI_DIALOG *, d_event *, void *))menu_handler, m ); x = MENU_BORDER+3; y = MENU_BORDER+3; for (i=0; ibutton_g[i] = ui_add_gadget_button( dlg, x, y, button_width, button_height, m->button[i], NULL ); y += button_height+MENU_VERT_SPACING; } choice = 0; while(choice==0) event_process(); ui_close_dialog(dlg); d_free(m->button); d_free(m->button_g); d_free(m); return choice; } dxx-rebirth-0.58.1-d1x/ui/menubar.c000066400000000000000000000427551217717257200170010ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include #include "physfsx.h" #include "u_mem.h" #include "fix.h" #include "pstypes.h" #include "gr.h" #include "event.h" #include "window.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "func.h" #include "dxxerror.h" #define MAXMENUS 30 #define MAXITEMS 40 typedef struct { short x, y, w, h; char *Text; char *InactiveText; short Hotkey; int (*user_function)(void); } ITEM; typedef struct { window *wind; short x, y, w, h; short ShowBar; short CurrentItem; short NumItems; short Displayed; short Active; ITEM Item[MAXITEMS]; } MENU; MENU Menu[MAXMENUS]; static int num_menus = 0; static int state; #define CMENU (Menu[0].CurrentItem+1) int menubar_handler(window *wind, d_event *event, MENU *menu); int menu_handler(window *wind, d_event *event, MENU *menu); //------------------------- Show a menu item ------------------- void item_show( MENU * menu, int n ) { ITEM * item = &menu->Item[n]; gr_set_current_canvas(NULL); // If this is a seperator, then draw it. if ( item->Text[0] == '-' ) { gr_setcolor( CBLACK ); gr_urect( item->x, item->y+item->h/2, item->x+item->w-1, item->y+item->h/2 ); return; } if ( menu->CurrentItem==n && menu->ShowBar ) { if ( menu != &Menu[0] ) { gr_setcolor( CBLACK ); gr_urect( item->x+1, item->y+1, item->x+menu->w-2, item->y+item->h-2 ); } gr_set_fontcolor( CWHITE, CBLACK ); }else { if ( menu != &Menu[0] ) { gr_setcolor( CGREY ); gr_urect( item->x+1, item->y+1, item->x+menu->w-2, item->y+item->h-2 ); } gr_set_fontcolor( CBLACK, CGREY ); } if ( menu != &Menu[0] ) { if ( menu->Active) gr_ustring( item->x+1, item->y+1, item->Text ); else gr_ustring( item->x+1, item->y+1, item->InactiveText ); } else { if ( menu->Active) gr_ustring( item->x, item->y, item->Text ); else gr_ustring( item->x, item->y, item->InactiveText ); } } void menu_draw(MENU *menu) { int i; gr_set_current_canvas(NULL); // Draw the menu background gr_setcolor( CGREY ); gr_urect( menu->x, menu->y, menu->x + menu->w - 1, menu->y + menu->h - 1 ); if ( menu != &Menu[0] ) { gr_setcolor( CBLACK ); gr_ubox( menu->x, menu->y, menu->x + menu->w - 1, menu->y + menu->h - 1 ); } // Draw the items for (i=0; i< menu->NumItems; i++ ) item_show( menu, i ); } //---------------------------- Show a menu --------------------- void menu_show( MENU * menu ) { if (!menu->wind) { menu->wind = window_create(&grd_curscreen->sc_canvas, menu->x, menu->y, menu->w, menu->h, (int (*)(window *, d_event *, void *)) ((menu == &Menu[0]) ? menubar_handler : menu_handler), menu); if (!menu->wind) return; if (menu == &Menu[0]) window_set_modal(Menu[0].wind, 0); // allow windows behind the menubar to accept events (e.g. the keypad dialogs) } window_set_visible(menu->wind, 1); // Mark as displayed. menu->Displayed = 1; } //-------------------------- Hide a menu ----------------------- void menu_hide( MENU * menu ) { // Can't hide if it's not already drawn if (!menu->Displayed) return; if ((menu != &Menu[0]) && menu->wind) window_set_visible(menu->wind, 0); // don't draw or receive events menu->Active = 0; if (Menu[0].wind && menu == &Menu[0]) window_set_modal(Menu[0].wind, 0); // Mark as hidden. menu->Displayed = 0; } //------------------------- Move the menu bar ------------------ void menu_move_bar_to( MENU * menu, int number ) { int old_item; old_item = menu->CurrentItem; menu->CurrentItem = number; if (menu->Displayed && (number != old_item)) { item_show( menu, old_item ); item_show( menu, number ); } } //------------------------ Match keypress to item ------------------ int menu_match_keypress( MENU * menu, int keypress ) { int i; char c; char *letter; if ((keypress & KEY_CTRLED) || (keypress & KEY_SHIFTED)) return -1; keypress &= 0xFF; c = key_ascii(); for (i=0; i< menu->NumItems; i++ ) { letter = strrchr( menu->Item[i].Text, CC_UNDERLINE ); if (letter) { letter++; if (c==tolower(*letter)) return i; } } return -1; } int menu_is_mouse_on( ITEM * item ) { int x, y, z; mouse_get_pos(&x, &y, &z); if ((x >= item->x) && (x < item->x + item->w ) && (y >= item->y) && (y <= item->y + item->h ) ) return 1; else return 0; } int menu_check_mouse_item( MENU * menu ) { int i; for (i=0; iNumItems; i++ ) { if (menu_is_mouse_on( &menu->Item[i] )) { if (menu->Item[i].Text[0] == '-') return -1; else return i; } } return -1; } void menu_hide_all() { int i; for (i=1; itype == EVENT_KEY_COMMAND) keypress = event_key_get(event); Menu[0].Active = 0; if (Menu[0].wind) window_set_modal(Menu[0].wind, 0); Menu[0].ShowBar = 0; if ( keypress & KEY_ALTED ) { i = menu_match_keypress( &Menu[0], keypress ); if (i > -1 ) { Menu[0].CurrentItem = i; Menu[0].Active = 0; if (Menu[0].wind) window_set_modal(Menu[0].wind, 0); state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].ShowBar = 1; menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); return 1; } } for (i=0; i -1)) { Menu[0].CurrentItem = i; state = 3; Menu[ CMENU ].ShowBar = 1; Menu[0].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); return 1; } return 0; } int do_state_1(d_event *event) { int i; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); if ((event->type == EVENT_KEY_RELEASE) && !(event_key_get(event) & KEY_ALTED)) { state = 2; state2_alt_down = 0; Menu[0].ShowBar = 1; Menu[0].Active = 1; menu_show( &Menu[0] ); #if 0 state = 0; menu_hide_all(); #endif rval = 1; } i = menu_match_keypress( &Menu[0], keypress ); if (i > -1 ) { Menu[0].CurrentItem = i; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].ShowBar = 1; menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); rval = 1; } i = menu_check_mouse_item( &Menu[0] ); if ( (i == -1) && B1_JUST_RELEASED ) { state = 0; menu_hide_all(); rval = 1; } if ( B1_JUST_PRESSED && (i > -1)) { Menu[0].CurrentItem = i; state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].ShowBar = 1; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); rval = 1; } return rval; } int do_state_2(d_event *event) { int i; int keypress = 0; int rval = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); if (keypress & KEY_ALTED) { state2_alt_down = 1; rval = 1; } if ((event->type == EVENT_KEY_RELEASE) && !(event_key_get(event) & KEY_ALTED) && state2_alt_down) { state = 0; menu_hide_all(); rval = 1; } switch( keypress ) { case KEY_ESC: state = 0; menu_hide_all(); rval = 1; break; case KEY_LEFT: case KEY_PAD4: i = Menu[0].CurrentItem-1; if (i < 0 ) i = Menu[0].NumItems-1; menu_move_bar_to( &Menu[0], i ); rval = 1; break; case KEY_RIGHT: case KEY_PAD6: i = Menu[0].CurrentItem+1; if (i >= Menu[0].NumItems ) i = 0; menu_move_bar_to( &Menu[0], i ); rval = 1; break; case KEY_ENTER: case KEY_PADENTER: case KEY_DOWN: case KEY_PAD2: state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); menu_show( &Menu[ 0 ] ); menu_show( &Menu[ CMENU ] ); rval = 1; break; default: i = menu_match_keypress( &Menu[0], keypress ); if (i > -1 ) { Menu[0].CurrentItem = i; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].ShowBar = 1; menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); rval = 1; break; } i = menu_check_mouse_item( &Menu[0] ); if ( (i == -1) && B1_JUST_RELEASED ) { state = 0; menu_hide_all(); rval = 1; break; } if (i > -1) { Menu[0].CurrentItem = i; Menu[0].Active = 0; window_set_modal(Menu[0].wind, 0); state = 3; Menu[ CMENU ].ShowBar = 1; Menu[ CMENU ].Active = 1; Menu[0].ShowBar = 1; menu_show( &Menu[ CMENU ] ); menu_show( &Menu[0] ); rval = 1; break; } } return rval; } int menu_handler(window *wind, d_event *event, MENU *menu) { int i; int keypress = 0; int rval = 0; if (state != 3) return 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); else if (event->type == EVENT_WINDOW_CLOSE) // quitting { state = 0; menu_hide_all(); menu->wind = NULL; return 0; } switch( keypress ) { case 0: break; case KEY_ESC: state = 0; menu_hide_all(); rval = 1; break; case KEY_DOWN: case KEY_PAD2: i = Menu[ CMENU ].CurrentItem; do { i++; if ( i >= Menu[ CMENU ].NumItems ) i = 0; } while( Menu[CMENU].Item[i].Text[0] == '-'); menu_move_bar_to( &Menu[ CMENU ], i ); rval = 1; break; case KEY_UP: case KEY_PAD8: i = Menu[ CMENU ].CurrentItem; do { i--; if ( i < 0 ) i = Menu[ CMENU ].NumItems-1; } while( Menu[CMENU].Item[i].Text[0] == '-'); menu_move_bar_to( &Menu[ CMENU ], i ); rval = 1; break; case KEY_RIGHT: case KEY_PAD6: menu_hide( &Menu[ CMENU ] ); i = Menu[0].CurrentItem+1; if (i >= Menu[0].NumItems ) i = 0; menu_move_bar_to( &Menu[0], i ); Menu[CMENU].ShowBar = 1; Menu[CMENU].Active = 1; menu_show( &Menu[CMENU] ); rval = 1; break; case KEY_LEFT: case KEY_PAD4: menu_hide( &Menu[ CMENU ] ); i = Menu[0].CurrentItem-1; if (i < 0 ) i = Menu[0].NumItems-1; menu_move_bar_to( &Menu[0], i ); Menu[ CMENU ].ShowBar = 1; Menu[CMENU].Active = 1; menu_show( &Menu[ CMENU ] ); rval = 1; break; case KEY_ENTER: case KEY_PADENTER: state = 0; menu_hide_all(); if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function) Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function(); rval = 1; break; default: i = menu_match_keypress( &Menu[ CMENU ], keypress ); if (i > -1 ) { menu_move_bar_to( &Menu[ CMENU ], i ); state = 0; menu_hide_all(); if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function) Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function(); rval = 1; break; } } if (event->type == EVENT_MOUSE_MOVED || B1_JUST_RELEASED) { i = menu_check_mouse_item( &Menu[CMENU] ); if (i > -1 ) { if ( B1_JUST_RELEASED ) { menu_move_bar_to( &Menu[ CMENU ], i ); state = 0; menu_hide_all(); if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function) Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function(); rval = 1; } else { menu_move_bar_to( &Menu[ CMENU ], i ); rval = 1; } } else { i = menu_check_mouse_item( &Menu[0] ); if (i > -1) { if ( Menu[0].CurrentItem != i) { menu_hide( &Menu[ CMENU ] ); menu_move_bar_to( &Menu[0], i ); Menu[ CMENU ].ShowBar = 1; Menu[CMENU].Active = 1; menu_show( &Menu[ CMENU ] ); } rval = 1; } if ( B1_JUST_RELEASED ) { state = 0; menu_hide_all(); rval = 1; } } } if (event->type == EVENT_WINDOW_DRAW) { menu_draw(&Menu[CMENU]); rval = 1; } return rval; } int menubar_handler(window *wind, d_event *event, MENU *menu) { int rval = 0; if (event->type == EVENT_WINDOW_DRAW) { menu_draw(&Menu[0]); return 1; } else if (event->type == EVENT_WINDOW_CLOSE) { int i; //menu_hide_all(); //menu_hide( &Menu[0] ); for (i=1; i= MAXMENUS) Error("Too many menus (%d).",menu); CommaParse( 1, buf1, buffer ); item = atoi(buf1 ); if (item >= MAXITEMS) Error("Too many items (%d) in menu %d.",item+1,menu); CommaParse( 2, buf1, buffer ); ul_xlate(buf1); if (buf1[0] != '-' ) { sprintf( buf2, " %s ", buf1 ); Menu[menu].Item[item].Text = d_strdup(buf2); } else Menu[menu].Item[item].Text = d_strdup(buf1); Menu[menu].Item[item].InactiveText = d_strdup(Menu[menu].Item[item].Text); j= 0; for (i=0; i<=strlen(Menu[menu].Item[item].Text); i++ ) { np = Menu[menu].Item[item].Text[i]; if (np != CC_UNDERLINE) Menu[menu].Item[item].InactiveText[j++] = np; } CommaParse( 3, buf1, buffer ); if (buf1[0]=='{' && buf1[1] =='}') Menu[menu].Item[item].Hotkey = -1; else { i = DecodeKeyText(buf1); if (i<1) { Error("Unknown key, %s, in %s\n", buf1, file ); } else { Menu[menu].Item[item].Hotkey = i; } } CommaParse( 4, buf1, buffer ); if (strlen(buf1)) { Menu[menu].Item[item].user_function = func_get(buf1, &np); if (Menu[menu].Item[item].user_function==NULL) { Error( "Unknown function, %s, in %s\n", buf1, file ); //ui_messagebox( -2, -2, 1, buffer, "Ok" ); } } Menu[menu].Item[item].x = Menu[menu].x; Menu[menu].Item[item].y = Menu[menu].y; if ( Menu[menu].Item[item].Text[0] == '-' ) { w = 1; h = 3; } else { gr_get_string_size( Menu[menu].Item[item].Text, &w, &h, &aw ); w += 2; h += 2; } if (menu==0) { Menu[0].h = h; Menu[0].Item[item].x = Menu[0].x + Menu[0].w; Menu[0].Item[item].y = Menu[0].y; Menu[item+1].x = Menu[0].x + Menu[0].w; Menu[item+1].y = Menu[0].h - 2; Menu[0].Item[item].w = w; Menu[0].Item[item].h = h; Menu[0].w += w; }else { if ( w > Menu[menu].w ) { Menu[menu].w = w; for (i=0; i< Menu[menu].NumItems; i++ ) Menu[menu].Item[i].w = Menu[menu].w; } Menu[menu].Item[item].w = Menu[menu].w; Menu[menu].Item[item].x = Menu[menu].x; Menu[menu].Item[item].y = Menu[menu].y+Menu[menu].h; Menu[menu].Item[item].h = h; Menu[menu].h += h; } if ( item >= Menu[menu].NumItems ) { Menu[menu].NumItems = item+1; } if ( menu >= num_menus ) num_menus = menu+1; } Menu[0].w = 700; PHYSFS_close( infile ); } void menubar_hide() { state = 0; menu_hide_all(); menu_hide( &Menu[0] ); } void menubar_show() { menu_show( &Menu[0] ); } void menubar_close() { if (!Menu[0].wind) return; window_close(Menu[0].wind); Menu[0].wind = NULL; } dxx-rebirth-0.58.1-d1x/ui/message.c000066400000000000000000000114001217717257200167530ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "fix.h" #include "pstypes.h" #include "gr.h" #include "event.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "u_mem.h" // ts = total span // w = width of each item // n = number of items // i = item number (0 based) #define EVEN_DIVIDE(ts,w,n,i) ((((ts)-((w)*(n)))*((i)+1))/((n)+1))+((w)*(i)) #define BUTTON_HORZ_SPACING 20 #define TEXT_EXTRA_HEIGHT 5 typedef struct messagebox { char **button; UI_GADGET_BUTTON *button_g[10]; char *text; int *choice; int num_buttons; int width; int text_y; int line_y; } messagebox; static int messagebox_handler(UI_DIALOG *dlg, d_event *event, messagebox *m) { int i; if (event->type == EVENT_UI_DIALOG_DRAW) { grs_font * temp_font; gr_set_current_canvas( &grd_curscreen->sc_canvas ); temp_font = grd_curscreen->sc_canvas.cv_font; if ( grd_curscreen->sc_w < 640 ) { grd_curscreen->sc_canvas.cv_font = ui_small_font; } ui_dialog_set_current_canvas(dlg); ui_string_centered( m->width/2, m->text_y, m->text ); gr_setcolor( CGREY ); Hline(1, m->width-2, m->line_y+1 ); gr_setcolor( CBRIGHT ); Hline(2, m->width-2, m->line_y+2 ); grd_curscreen->sc_canvas.cv_font = temp_font; return 1; } for (i=0; inum_buttons; i++ ) { if (GADGET_PRESSED(m->button_g[i])) { *(m->choice) = i+1; return 1; } } return 0; } int ui_messagebox_n( short xc, short yc, int NumButtons, char * text, char * Button[] ) { UI_DIALOG * dlg; messagebox *m; int i, width, height, avg, x, y; int button_width, button_height, text_height, text_width; int w, h; int choice; if ((NumButtons < 1) || (NumButtons>10)) return -1; MALLOC(m, messagebox, 1); m->button = Button; m->text = text; m->choice = &choice; m->num_buttons = NumButtons; button_width = button_height = 0; gr_set_current_canvas( &grd_curscreen->sc_canvas ); w = grd_curscreen->sc_w; h = grd_curscreen->sc_h; for (i=0; i button_width ) button_width = width; if ( height > button_height ) button_height = height; } gr_get_string_size(text, &text_width, &text_height, &avg ); width = button_width*NumButtons; width += BUTTON_HORZ_SPACING*(NumButtons+1); width ++; text_width += avg*6; text_width += 10; if (text_width > width ) width = text_width; height = text_height; height += button_height; height += 4*TEXT_EXTRA_HEIGHT; height += 2; // For line in middle { int mx, my, mz; mouse_get_pos(&mx, &my, &mz); if ( xc == -1 ) xc = mx; if ( yc == -1 ) yc = my - button_height/2; } if ( xc == -2 ) xc = w/2; if ( yc == -2 ) yc = h/2; x = xc - width/2; y = yc - height/2; if (x < 0 ) { x = 0; } if ( (x+width-1) >= w ) { x = w - width; } if (y < 0 ) { y = 0; } if ( (y+height-1) >= h ) { y = h - height; } dlg = ui_create_dialog( x, y, width, height, DF_DIALOG | DF_MODAL, (int (*)(UI_DIALOG *, d_event *, void *))messagebox_handler, m ); //ui_draw_line_in( MESSAGEBOX_BORDER, MESSAGEBOX_BORDER, width-MESSAGEBOX_BORDER, height-MESSAGEBOX_BORDER ); y = TEXT_EXTRA_HEIGHT + text_height/2 - 1; m->width = width; m->text_y = y; y = 2*TEXT_EXTRA_HEIGHT + text_height; m->line_y = y; y = height - TEXT_EXTRA_HEIGHT - button_height; for (i=0; ibutton_g[i] = ui_add_gadget_button( dlg, x, y, button_width, button_height, Button[i], NULL ); } ui_gadget_calc_keys(dlg); //key_flush(); dlg->keyboard_focus_gadget = (UI_GADGET *)m->button_g[0]; choice = 0; while(choice==0) event_process(); ui_close_dialog(dlg); return choice; } int ui_messagebox( short xc, short yc, int NumButtons, char * text, ... ) { va_list marker; char * Button[10]; short i; if ((NumButtons < 1) || (NumButtons>10)) return -1; va_start( marker, text ); for (i=0; inum_buttons; i++ ) { if (GADGET_PRESSED(p->button_g[i])) { *(p->choice) = i+1; return 1; } } if ( (*(p->choice)==0) && B1_JUST_RELEASED ) { *(p->choice) = -1; return 1; } return 0; } // Use: Left button (button 0) goes down, then up, then this is called // as opposed to straight after the button goes down, holding down // until an option is chosen. // This is like the 'modern' behaviour of popup menus and also happens // to be easier to implement because of the button code. // Recommended for use in conjunction with a button gadget, // i.e. when that button is pressed, call PopupMenu, // update the button's text then the value in question. int PopupMenu( int NumButtons, char * text[] ) { UI_DIALOG * dlg; popup *p; char * Button[10]; int button_width, button_height, width, height; short i, x, y; short w, h; int choice; MALLOC(p, popup, 1); p->num_buttons = NumButtons; p->choice = &choice; if ((NumButtons < 1) || (NumButtons>10)) { d_free(p); return -1; } button_width = button_height = 0; gr_set_current_canvas( &grd_curscreen->sc_canvas ); for (i=0; i button_width ) button_width = width; if ( height > button_height ) button_height = height; } width = button_width + 2*(MENU_BORDER+3); height = (button_height*NumButtons) + (MENU_VERT_SPACING*(NumButtons-1)) ; height += (MENU_BORDER+3) * 2; { int mx, my, mz; mouse_get_pos(&mx, &my, &mz); x = mx - width/2; y = my - (MENU_BORDER+3) - button_height/2; } w = grd_curscreen->sc_w; h = grd_curscreen->sc_h; if (x < 0 ) { x = 0; //Mouse.x = x + width / 2; } if ( (x+width-1) >= w ) { x = w - width; //Mouse.x = x + width / 2; } if (y < 0 ) { y = 0; //Mouse.y = y + (MENU_BORDER+3) + button_height/2; } if ( (y+height-1) >= h ) { y = h - height; //Mouse.y = y + (MENU_BORDER+3) + button_height/2; } dlg = ui_create_dialog( x, y, width, height, DF_DIALOG | DF_MODAL, (int (*)(UI_DIALOG *, d_event *, void *))popup_handler, p ); //mouse_set_pos(Mouse.x, Mouse.y); x = MENU_BORDER+3; y = MENU_BORDER+3; for (i=0; ibutton_g[i] = ui_add_gadget_button( dlg, x, y, button_width, button_height, Button[i], NULL ); y += button_height+MENU_VERT_SPACING; } choice = 0; while(choice==0) event_process(); ui_close_dialog(dlg); d_free(p); return choice; } dxx-rebirth-0.58.1-d1x/ui/radio.c000066400000000000000000000104701217717257200164330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Radio box gadget stuff. * */ #include #include #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "u_mem.h" #include "strutil.h" #define Middle(x) ((2*(x)+1)/4) void ui_draw_radio( UI_DIALOG *dlg, UI_GADGET_RADIO * radio ) { #if 0 //ndef OGL if ((radio->status==1) || (radio->position != radio->oldposition)) #endif { radio->status = 0; gr_set_current_canvas( radio->canvas ); if (dlg->keyboard_focus_gadget == (UI_GADGET *) radio) gr_set_fontcolor(CRED, -1); else gr_set_fontcolor(CBLACK, -1); if (radio->position == 0 ) { ui_draw_box_out( 0, 0, radio->width-1, radio->height-1 ); if (radio->flag) ui_string_centered(Middle(radio->width), Middle(radio->height), "O"); else ui_string_centered(Middle(radio->width), Middle(radio->height), " "); } else { ui_draw_box_in( 0, 0, radio->width-1, radio->height-1 ); if (radio->flag) ui_string_centered(Middle(radio->width) + 1, Middle(radio->height) + 1, "O"); else ui_string_centered(Middle(radio->width) + 1, Middle(radio->height) + 1, " "); } gr_ustring( radio->width+4, 2, radio->text ); } } UI_GADGET_RADIO * ui_add_gadget_radio( UI_DIALOG * dlg, short x, short y, short w, short h, short group, char * text ) { UI_GADGET_RADIO * radio; radio = (UI_GADGET_RADIO *)ui_gadget_add( dlg, 4, x, y, x+w-1, y+h-1 ); radio->text = d_strdup(text); radio->width = w; radio->height = h; radio->position = 0; radio->oldposition = 0; radio->pressed = 0; radio->flag = 0; radio->group = group; return radio; } int ui_radio_do( UI_DIALOG *dlg, UI_GADGET_RADIO * radio, d_event *event ) { UI_GADGET * tmp; UI_GADGET_RADIO * tmpr; int rval = 0; radio->oldposition = radio->position; radio->pressed = 0; if (event->type == EVENT_MOUSE_BUTTON_DOWN || event->type == EVENT_MOUSE_BUTTON_UP) { int OnMe; OnMe = ui_mouse_on_gadget( (UI_GADGET *)radio ); if ( B1_JUST_PRESSED && OnMe) { radio->position = 1; rval = 1; } else if (B1_JUST_RELEASED) { if ((radio->position==1) && OnMe) radio->pressed = 1; radio->position = 0; } } if (event->type == EVENT_KEY_COMMAND) { int key; key = event_key_get(event); if ((dlg->keyboard_focus_gadget==(UI_GADGET *)radio) && ((key==KEY_SPACEBAR) || (key==KEY_ENTER)) ) { radio->position = 2; rval = 1; } } else if (event->type == EVENT_KEY_RELEASE) { int key; key = event_key_get(event); radio->position = 0; if ((dlg->keyboard_focus_gadget==(UI_GADGET *)radio) && ((key==KEY_SPACEBAR) || (key==KEY_ENTER)) ) radio->pressed = 1; } if ((radio->pressed == 1) && (radio->flag==0)) { tmp = (UI_GADGET *)radio->next; while (tmp != (UI_GADGET *)radio ) { if (tmp->kind==4) { tmpr = (UI_GADGET_RADIO *)tmp; if ((tmpr->group == radio->group ) && (tmpr->flag) ) { tmpr->flag = 0; tmpr->status = 1; tmpr->pressed = 0; } } tmp = tmp->next; } radio->flag = 1; ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)radio); rval = 1; } if (event->type == EVENT_WINDOW_DRAW) ui_draw_radio( dlg, radio ); return rval; } void ui_radio_set_value(UI_GADGET_RADIO *radio, int value) { UI_GADGET_RADIO *tmp; value = value != 0; if (radio->flag == value) return; radio->flag = value; radio->status = 1; // redraw tmp = (UI_GADGET_RADIO *) radio->next; while (tmp != radio) { if ((tmp->kind == 4) && (tmp->group == radio->group) && tmp->flag) { tmp->flag = 0; tmp->status = 1; } tmp = (UI_GADGET_RADIO *) tmp->next; } } dxx-rebirth-0.58.1-d1x/ui/scroll.c000066400000000000000000000174761217717257200166500ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" #include "timer.h" void ui_draw_scrollbar( UI_DIALOG *dlg, UI_GADGET_SCROLLBAR * scrollbar ) { #if 0 //ndef OGL if (scrollbar->status==0) return; #endif scrollbar->status = 0; gr_set_current_canvas( scrollbar->canvas ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)scrollbar) gr_setcolor( CRED ); else gr_setcolor( CGREY ); gr_rect( 0, 0, scrollbar->width-1, scrollbar->fake_position-1 ); gr_rect( 0, scrollbar->fake_position+scrollbar->fake_size, scrollbar->width-1, scrollbar->height-1); ui_draw_box_out(0, scrollbar->fake_position, scrollbar->width-1, scrollbar->fake_position+scrollbar->fake_size-1 ); } UI_GADGET_SCROLLBAR * ui_add_gadget_scrollbar( UI_DIALOG * dlg, short x, short y, short w, short h, int start, int stop, int position, int window_size ) { int tw, th, taw; UI_GADGET_SCROLLBAR * scrollbar; char up[2]; char down[2]; up[0] = 30; up[1] = 0; down[0] = 31; down[1] = 0; gr_get_string_size( up, &tw, &th, &taw ); w = tw + 10; if (stop < start ) stop = start; scrollbar = (UI_GADGET_SCROLLBAR *)ui_gadget_add( dlg, 3, x, y+w, x+w-1, y+h-w-1 ); scrollbar->up_button = ui_add_gadget_button( dlg, x, y, w, w, up, NULL ); scrollbar->up_button->parent = (UI_GADGET *)scrollbar; scrollbar->down_button =ui_add_gadget_button( dlg, x, y+h-w, w, w, down, NULL ); scrollbar->down_button->parent = (UI_GADGET *)scrollbar; scrollbar->horz = 0; scrollbar->width = scrollbar->x2-scrollbar->x1+1; scrollbar->height = scrollbar->y2-scrollbar->y1+1; scrollbar->start = start; scrollbar->stop = stop; scrollbar->position = position; scrollbar->window_size = window_size; scrollbar->fake_length = scrollbar->height; scrollbar->fake_position = 0; if (stop!=start) scrollbar->fake_size = (window_size * scrollbar->height)/(stop-start+1+window_size); else scrollbar->fake_size = scrollbar->height; if (scrollbar->fake_size < 7) scrollbar->fake_size = 7; scrollbar->dragging = 0; scrollbar->moved=0; scrollbar->last_scrolled = 0; return scrollbar; } int ui_scrollbar_do( UI_DIALOG *dlg, UI_GADGET_SCROLLBAR * scrollbar, d_event *event ) { int OnMe, OnSlider, keyfocus; int oldpos, op; int x, y, z; int rval = 0; if (event->type == EVENT_WINDOW_DRAW) { ui_draw_scrollbar( dlg, scrollbar ); return 0; } keyfocus = 0; if (dlg->keyboard_focus_gadget==(UI_GADGET *)scrollbar) keyfocus = 1; if (scrollbar->start==scrollbar->stop) { scrollbar->position = 0; scrollbar->fake_position = 0; ui_draw_scrollbar( dlg, scrollbar ); return 0; } op = scrollbar->position; oldpos = scrollbar->fake_position; scrollbar->moved = 0; if (keyfocus && event->type == EVENT_KEY_COMMAND) { int key; key = event_key_get(event); if (key & KEY_UP) { scrollbar->up_button->position = 2; rval = 1; } else if (key & KEY_DOWN) { scrollbar->down_button->position = 2; rval = 1; } } else if (keyfocus && event->type == EVENT_KEY_RELEASE) { int key; key = event_key_get(event); if (key & KEY_UP) { scrollbar->up_button->position = 0; rval = 1; } else if (key & KEY_DOWN) { scrollbar->down_button->position = 0; rval = 1; } } if (scrollbar->up_button->position!=0) { if (timer_query() > scrollbar->last_scrolled + 1) { scrollbar->last_scrolled = timer_query(); scrollbar->position--; if (scrollbar->position < scrollbar->start ) scrollbar->position = scrollbar->start; scrollbar->fake_position = scrollbar->position-scrollbar->start; scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); } } if (scrollbar->down_button->position!=0) { if (timer_query() > scrollbar->last_scrolled + 1) { scrollbar->last_scrolled = timer_query(); scrollbar->position++; if (scrollbar->position > scrollbar->stop ) scrollbar->position = scrollbar->stop; scrollbar->fake_position = scrollbar->position-scrollbar->start; scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); } } OnMe = ui_mouse_on_gadget( (UI_GADGET *)scrollbar ); //gr_ubox(0, scrollbar->fake_position, scrollbar->width-1, scrollbar->fake_position+scrollbar->fake_size-1 ); if (B1_JUST_RELEASED) scrollbar->dragging = 0; //if (B1_PRESSED && OnMe ) // listbox->dragging = 1; mouse_get_pos(&x, &y, &z); OnSlider = 0; if ((y >= scrollbar->fake_position+scrollbar->y1) && \ (y < scrollbar->fake_position+scrollbar->y1+scrollbar->fake_size) && OnMe ) OnSlider = 1; if (B1_JUST_PRESSED && OnSlider ) { scrollbar->dragging = 1; scrollbar->drag_x = x; scrollbar->drag_y = y; scrollbar->drag_starting = scrollbar->fake_position; rval = 1; } else if (B1_JUST_PRESSED && OnMe) { scrollbar->dragging = 2; // outside the slider rval = 1; } if ((scrollbar->dragging == 2) && OnMe && !OnSlider && (timer_query() > scrollbar->last_scrolled + 4)) { scrollbar->last_scrolled = timer_query(); if ( y < scrollbar->fake_position+scrollbar->y1 ) { // Page Up scrollbar->position -= scrollbar->window_size; if (scrollbar->position < scrollbar->start ) scrollbar->position = scrollbar->start; } else { // Page Down scrollbar->position += scrollbar->window_size; if (scrollbar->position > scrollbar->stop ) scrollbar->position = scrollbar->stop; } scrollbar->fake_position = scrollbar->position-scrollbar->start; scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); } if ((selected_gadget==(UI_GADGET *)scrollbar) && (scrollbar->dragging == 1)) { //x = scrollbar->drag_x; scrollbar->fake_position = scrollbar->drag_starting + (y - scrollbar->drag_y ); if (scrollbar->fake_position<0) { scrollbar->fake_position = 0; //y = scrollbar->fake_position + scrollbar->drag_y - scrollbar->drag_starting; } if (scrollbar->fake_position > (scrollbar->height-scrollbar->fake_size)) { scrollbar->fake_position = (scrollbar->height-scrollbar->fake_size); //y = scrollbar->fake_position + scrollbar->drag_y - scrollbar->drag_starting; } //mouse_set_pos( x, y ); scrollbar->position = scrollbar->fake_position; scrollbar->position *= (scrollbar->stop-scrollbar->start); scrollbar->position /= ( scrollbar->height-scrollbar->fake_size ) ; scrollbar->position += scrollbar->start; if (scrollbar->position > scrollbar->stop ) scrollbar->position = scrollbar->stop; if (scrollbar->position < scrollbar->start ) scrollbar->position = scrollbar->start; //scrollbar->fake_position = scrollbar->position-scrollbar->start; //scrollbar->fake_position *= scrollbar->height-scrollbar->fake_size; //scrollbar->fake_position /= (scrollbar->stop-scrollbar->start); } if (op != scrollbar->position ) scrollbar->moved = 1; if (scrollbar->moved) { ui_gadget_send_event(dlg, EVENT_UI_GADGET_PRESSED, (UI_GADGET *)scrollbar); rval = 1; } if (oldpos != scrollbar->fake_position) scrollbar->status = 1; return rval; } dxx-rebirth-0.58.1-d1x/ui/ui.c000066400000000000000000000033331217717257200157520ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * UI init and close functions. * */ #include #include #include #include #include "fix.h" #include "pstypes.h" #include "gr.h" #include "key.h" #include "ui.h" #include "mouse.h" static int Initialized = 0; unsigned char CBLACK,CGREY,CWHITE,CBRIGHT,CRED; grs_font * ui_small_font = NULL; void ui_init() { grs_font * org_font; if (Initialized) return; Initialized = 1; org_font = grd_curcanv->cv_font; ui_small_font = gr_init_font( "pc6x8.fnt" ); grd_curcanv->cv_font =org_font; CBLACK = gr_find_closest_color( 1, 1, 1 ); CGREY = gr_find_closest_color( 45, 45, 45 ); CWHITE = gr_find_closest_color( 50, 50, 50 ); CBRIGHT = gr_find_closest_color( 58, 58, 58 ); CRED = gr_find_closest_color( 63, 0, 0 ); //key_init(); gr_set_fontcolor( CBLACK, CWHITE ); ui_pad_init(); atexit(ui_close ); } void ui_close() { if (Initialized) { Initialized = 0; menubar_close(); ui_pad_close(); gr_close_font( ui_small_font ); } return; } dxx-rebirth-0.58.1-d1x/ui/uidraw.c000066400000000000000000000054061217717257200166330ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include "fix.h" #include "pstypes.h" #include "gr.h" #include "ui.h" void Hline(short x1, short x2, short y ) { gr_uline( i2f(x1), i2f(y), i2f(x2), i2f(y) ); } void Vline(short y1, short y2, short x ) { gr_uline(i2f(x), i2f(y1), i2f(x), i2f(y2)); } void ui_string_centered( short x, short y, char * s ) { int height, width, avg; gr_get_string_size(s, &width, &height, &avg ); //baseline = height-grd_curcanv->cv_font->ft_baseline; gr_ustring(x-((width-1)/2), y-((height-1)/2), s ); } void ui_draw_shad( short x1, short y1, short x2, short y2, short c1, short c2 ) { gr_setcolor( c1 ); Hline( x1+0, x2-1, y1+0 ); Vline( y1+1, y2+0, x1+0 ); gr_setcolor( c2 ); Hline( x1+1, x2, y2-0 ); Vline( y1+0, y2-1, x2-0 ); } void ui_draw_frame( short x1, short y1, short x2, short y2 ) { ui_draw_shad( x1+0, y1+0, x2-0, y2-0, CBRIGHT, CGREY ); ui_draw_shad( x1+1, y1+1, x2-1, y2-1, CBRIGHT, CGREY ); ui_draw_shad( x1+2, y1+2, x2-2, y2-2, CWHITE, CWHITE ); ui_draw_shad( x1+3, y1+3, x2-3, y2-3, CWHITE, CWHITE ); ui_draw_shad( x1+4, y1+4, x2-4, y2-4, CWHITE, CWHITE ); ui_draw_shad( x1+5, y1+5, x2-5, y2-5, CWHITE, CWHITE ); ui_draw_shad( x1+6, y1+6, x2-6, y2-6, CGREY, CBRIGHT ); ui_draw_shad( x1+7, y1+7, x2-7, y2-7, CGREY, CBRIGHT ); } void ui_draw_box_out( short x1, short y1, short x2, short y2 ) { gr_setcolor( CWHITE ); gr_urect( x1+2, y1+2, x2-2, y2-2 ); ui_draw_shad( x1+0, y1+0, x2-0, y2-0, CBRIGHT, CGREY ); ui_draw_shad( x1+1, y1+1, x2-1, y2-1, CBRIGHT, CGREY ); } void ui_draw_box_in( short x1, short y1, short x2, short y2 ) { gr_setcolor( CWHITE ); // gr_urect( x1+2, y1+2, x2-2, y2-2 ); ui_draw_shad( x1+0, y1+0, x2-0, y2-0, CGREY, CBRIGHT ); ui_draw_shad( x1+1, y1+1, x2-1, y2-1, CGREY, CBRIGHT ); } void ui_draw_line_in( short x1, short y1, short x2, short y2 ) { gr_setcolor( CGREY ); Hline( x1, x2, y1 ); Hline( x1, x2-1, y2-1 ); Vline( y1+1, y2-2, x1 ); Vline( y1+1, y2-2, x2-1 ); gr_setcolor( CBRIGHT ); Hline( x1+1, x2-1, y1+1 ); Hline( x1, x2, y2 ); Vline( y1+2, y2-2, x1+1 ); Vline( y1+1, y2-1, x2 ); } dxx-rebirth-0.58.1-d1x/ui/userbox.c000066400000000000000000000072341217717257200170300ustar00rootroot00000000000000/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #include #include "fix.h" #include "pstypes.h" #include "event.h" #include "gr.h" #include "ui.h" #include "mouse.h" #include "key.h" void ui_draw_userbox( UI_DIALOG *dlg, UI_GADGET_USERBOX * userbox ) { #if 0 //ndef OGL if ( userbox->status==1 ) #endif { userbox->status = 0; gr_set_current_canvas( userbox->canvas ); if (dlg->keyboard_focus_gadget == (UI_GADGET *)userbox) gr_setcolor( CRED ); else gr_setcolor( CBRIGHT ); gr_ubox( -1, -1, userbox->width, userbox->height ); } } UI_GADGET_USERBOX * ui_add_gadget_userbox( UI_DIALOG * dlg, short x, short y, short w, short h ) { UI_GADGET_USERBOX * userbox; userbox = (UI_GADGET_USERBOX *)ui_gadget_add( dlg, 7, x, y, x+w-1, y+h-1 ); userbox->width = w; userbox->height = h; userbox->b1_held_down=0; userbox->b1_clicked=0; userbox->b1_double_clicked=0; userbox->b1_dragging=0; userbox->b1_drag_x1=0; userbox->b1_drag_y1=0; userbox->b1_drag_x2=0; userbox->b1_drag_y2=0; userbox->b1_done_dragging = 0; userbox->keypress = 0; userbox->mouse_onme = 0; userbox->mouse_x = 0; userbox->mouse_y = 0; userbox->bitmap = &(userbox->canvas->cv_bitmap); return userbox; } int ui_userbox_do( UI_DIALOG *dlg, UI_GADGET_USERBOX * userbox, d_event *event ) { int OnMe, olddrag; int x, y, z; int keypress = 0; int rval = 0; if (event->type == EVENT_WINDOW_DRAW) ui_draw_userbox( dlg, userbox ); if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); mouse_get_pos(&x, &y, &z); OnMe = ui_mouse_on_gadget( (UI_GADGET *)userbox ); olddrag = userbox->b1_held_down; userbox->mouse_onme = OnMe; userbox->mouse_x = x - userbox->x1; userbox->mouse_y = y - userbox->y1; userbox->b1_dragging = 0; userbox->b1_clicked = 0; if (OnMe) { if ( B1_JUST_PRESSED ) { userbox->b1_held_down = 1; userbox->b1_drag_x1 = x - userbox->x1; userbox->b1_drag_y1 = y - userbox->y1; rval = 1; } else if (B1_JUST_RELEASED) { if (userbox->b1_held_down) userbox->b1_clicked = 1; userbox->b1_held_down = 0; rval = 1; } if ( (event->type == EVENT_MOUSE_MOVED) && userbox->b1_held_down ) { userbox->b1_dragging = 1; userbox->b1_drag_x2 = x - userbox->x1; userbox->b1_drag_y2 = y - userbox->y1; } if ( B1_DOUBLE_CLICKED ) { userbox->b1_double_clicked = 1; rval = 1; } else userbox->b1_double_clicked = 0; } if (B1_JUST_RELEASED) userbox->b1_held_down = 0; userbox->b1_done_dragging = 0; if (olddrag==1 && userbox->b1_held_down==0 ) { if ((userbox->b1_drag_x1 != userbox->b1_drag_x2) || (userbox->b1_drag_y1 != userbox->b1_drag_y2) ) userbox->b1_done_dragging = 1; } if (dlg->keyboard_focus_gadget==(UI_GADGET *)userbox) { userbox->keypress = keypress; rval = 1; } if (userbox->b1_clicked || userbox->b1_dragging) { ui_gadget_send_event(dlg, userbox->b1_clicked ? EVENT_UI_GADGET_PRESSED : EVENT_UI_USERBOX_DRAGGED, (UI_GADGET *)userbox); rval = 1; } return rval; } dxx-rebirth-0.58.1-d1x/utilities/000077500000000000000000000000001217717257200165655ustar00rootroot00000000000000dxx-rebirth-0.58.1-d1x/utilities/SConstruct000066400000000000000000000032331217717257200206200ustar00rootroot00000000000000#SConstruct # needed imports import sys import os import SCons.Util PROGRAM_NAME = 'MacD1Extract' print '\n===== ' + PROGRAM_NAME + ' =====\n' # source files sources = [ 'extractD1Data.cpp' ] # Acquire environment object... env = Environment(ENV = os.environ) # Prettier build messages...... env["CCCOMSTR"] = "Compiling $SOURCE ..." env["CXXCOMSTR"] = "Compiling $SOURCE ..." env["LINKCOMSTR"] = "Linking $TARGET ..." env["ARCOMSTR"] = "Archiving $TARGET ..." env["RANLIBCOMSTR"] = "Indexing $TARGET ..." # Get traditional compiler environment variables if os.environ.has_key('CC'): env['CC'] = os.environ['CC'] if os.environ.has_key('CFLAGS'): env['CCFLAGS'] += SCons.Util.CLVar(os.environ['CFLAGS']) if os.environ.has_key('CXX'): env['CXX'] = os.environ['CXX'] if os.environ.has_key('CXXFLAGS'): env['CXXFLAGS'] += SCons.Util.CLVar(os.environ['CXXFLAGS']) if os.environ.has_key('LDFLAGS'): env['LINKFLAGS'] += SCons.Util.CLVar(os.environ['LDFLAGS']) # windows or *nix? if sys.platform == 'win32': print "compiling on Windows" winlibs = ['winmm', 'mingw32'] # are these even needed? libs = winlibs lflags = '-mwindows' elif sys.platform == 'darwin': print "compiling on Mac OS X" libs = '' lflags = '' else: print "compiling on *NIX" libs = '' lflags = '' target = 'macd1extract' print '\n' # building program... env.Program(target=str(target), source = sources, LIBS = libs, LINKFLAGS = str(lflags)) # show some help when running scons -h Help(PROGRAM_NAME + ', SConstruct file help:' + """ Type 'scons' to build the binary. Type 'scons install' to build (if it hasn't been done) and install. Type 'scons -c' to clean up. """) #EOF dxx-rebirth-0.58.1-d1x/utilities/extractD1Data.cpp000066400000000000000000000120141217717257200217200ustar00rootroot00000000000000/* * extractD1Data.cpp * * * Created by Peter "halprin" Kendall on 8/26/09. * Copyright 2009 @PAK Software. All rights reserved. * */ #define DEFAULT_INSTALL_LOCATION "/Volumes/Descent/Install Descent" #define CHAOS_HOG_SIZE 0x2AA9F #define CHAOS_HOG_OFFSET 0xAF310 #define CHAOS_MSN_REZ_SIZE 0x14C #define CHAOS_MSN_REZ_OFFSET 0xD9E1F #define CHAOS_MSN_SIZE 0x12B #define CHAOS_MSN_OFFSET 0xD9F6B #define DESCENT_HOG_SIZE 0x71C5B3 #define DESCENT_HOG_OFFSET 0xDA106 #define DESCENT_PIG_SIZE 0x3CA96D #define DESCENT_PIG_OFFSET 0x7F6729 #include #include #include using namespace std; void printUsage(); int main(int argc, char **argv) { string install_location=DEFAULT_INSTALL_LOCATION; if(argc>2 || (argc==2 && strcmp(argv[1], "-help")==0)) { printUsage(); return -1; } else if(argc==2) { //use a custom location for the installer install_location=argv[1]; } //report what we are doing cout << endl; cout << "DETAILS" << endl; cout << "Installer: " << install_location << endl; ifstream installer(install_location.c_str()); if(!installer) { cout << "Error: Cannot open the installer file." << endl; cout << "Does it exist at the location specified?" << endl << endl; printUsage(); return -2; } //report more on what we are doing cout << "CHAOS.HOG:" << endl; cout << " starts 0x" << hex << uppercase << CHAOS_HOG_OFFSET << endl; cout << " size 0x" << hex << uppercase << CHAOS_HOG_SIZE << endl; cout << "CHAOS.MSN:" << endl; cout << " starts 0x" << hex << uppercase << CHAOS_MSN_OFFSET << endl; cout << " size 0x" << hex << uppercase << CHAOS_MSN_SIZE << endl; cout << "CHAOS.MSN resource fork:" << endl; cout << " starts 0x" << hex << uppercase << CHAOS_MSN_REZ_OFFSET << endl; cout << " size 0x" << hex << uppercase << CHAOS_MSN_REZ_SIZE << endl; cout << "descent.hog:" << endl; cout << " starts 0x" << hex << uppercase << DESCENT_HOG_OFFSET << endl; cout << " size 0x" << hex << uppercase << DESCENT_HOG_SIZE << endl; cout << "descent.pig:" << endl; cout << " starts 0x" << hex << uppercase << DESCENT_PIG_OFFSET << endl; cout << " size 0x" << hex << uppercase << DESCENT_PIG_SIZE << endl; cout << endl; char* chaos_hog_buffer=(char*)malloc(CHAOS_HOG_SIZE); char* chaos_msn_rez_buffer=(char*)malloc(CHAOS_MSN_REZ_SIZE); char* chaos_msn_buffer=(char*)malloc(CHAOS_MSN_SIZE); char* descent_hog_buffer=(char*)malloc(DESCENT_HOG_SIZE); char* descent_pig_buffer=(char*)malloc(DESCENT_PIG_SIZE); ofstream chaos_hog_file("CHAOS.HOG"); if(!chaos_hog_file) { cout << "Error: Unable to create new CHAOS.HOG file. Skipping!" << endl; } ofstream chaos_msn_file("CHAOS.MSN"); if(!chaos_msn_file) { cout << "Error: Unable to create new CHAOS.MSN file. Skipping!" << endl; } ofstream chaos_msn_rez_file("CHAOS.MSN/..namedfork/rsrc"); if(!chaos_msn_rez_file) { cout << "Error: Unable to create the resource fork of the CHAOS.MSN file. Skipping!" << endl; } ofstream descent_hog_file("descent.hog"); if(!descent_hog_file) { cout << "Error: Unable to create new descent.hog file. Skipping!" << endl; } ofstream descent_pig_file("descent.pig"); if(!descent_pig_file) { cout << "Error: Unable to create new descent.pig file. Skipping!" << endl; } //read the CHAOS.HOG file installer.ignore(CHAOS_HOG_OFFSET); installer.read(chaos_hog_buffer, CHAOS_HOG_SIZE); //write the CHAOS.HOG file chaos_hog_file.write(chaos_hog_buffer, CHAOS_HOG_SIZE); //read the CHAOS.MSN file's resource fork installer.ignore(CHAOS_MSN_REZ_OFFSET-(CHAOS_HOG_OFFSET+CHAOS_HOG_SIZE)); installer.read(chaos_msn_rez_buffer, CHAOS_MSN_REZ_SIZE); //write the CHAOS.MSN file's resource fork chaos_msn_rez_file.write(chaos_msn_rez_buffer, CHAOS_MSN_REZ_SIZE); //read the CHAOS.MSN file installer.ignore(CHAOS_MSN_OFFSET-(CHAOS_MSN_REZ_OFFSET+CHAOS_MSN_REZ_SIZE)); installer.read(chaos_msn_buffer, CHAOS_MSN_SIZE); //write the CHAOS.MSN file chaos_msn_file.write(chaos_msn_buffer, CHAOS_MSN_SIZE); //read the descent.hog file installer.ignore(DESCENT_HOG_OFFSET-(CHAOS_MSN_OFFSET+CHAOS_MSN_SIZE)); installer.read(descent_hog_buffer, DESCENT_HOG_SIZE); //write the descent.hog file descent_hog_file.write(descent_hog_buffer, DESCENT_HOG_SIZE); //read the descent.pig file installer.ignore(DESCENT_PIG_OFFSET-(DESCENT_HOG_OFFSET+DESCENT_HOG_SIZE)); installer.read(descent_pig_buffer, DESCENT_PIG_SIZE); //write the descent.pig file descent_pig_file.write(descent_pig_buffer, DESCENT_PIG_SIZE); //Done! cout << "Extraction complete!" << endl << endl; free(chaos_hog_buffer); free(chaos_msn_rez_buffer); free(chaos_msn_buffer); free(descent_hog_buffer); free(descent_pig_buffer); chaos_hog_file.close(); chaos_msn_file.close(); chaos_msn_rez_file.close(); descent_hog_file.close(); descent_pig_file.close(); return 0; } void printUsage() { cout << "Usage: ./d1Extract " << endl; cout << "If is not specified, the default \"" << DEFAULT_INSTALL_LOCATION << "\" will be used." << endl << endl; }

q c #E2FEFF", ",q c #F3FFFF", "'q c #BDFCFF", ")q c #A9F9FF", "!q c #CCFCFC", "~q c #CBE5F3", "{q c #7ABDE5", "]q c #4199D7", "^q c #478BCE", "/q c #498BC9", "(q c #478FC8", "_q c #458FC6", ":q c #418ABF", "r c #4A92CE", ",r c #4D94CC", "'r c #4993CB", ")r c #4991CA", "!r c #478FC6", "~r c #468FC6", "{r c #4490C7", "]r c #3F88BB", "^r c #3E88BB", "/r c #3B85B7", "(r c #367FB2", "_r c #357EB0", ":r c #3179A9", "s c #296A98", ",s c #28699A", "'s c #3481AC", ")s c #2E76A3", "!s c #1A649B", "~s c #2B73A9", "{s c #81877A", "]s c #B87A3A", "^s c #EA8820", "/s c #F08B1D", "(s c #E9871C", "_s c #F68F1F", ":s c #F48A1D", "t c #2C719E", ",t c #17619D", "'t c #3675A3", ")t c #89826E", "!t c #AD6C31", "~t c #DA7C1C", "{t c #F08C1C", "]t c #F9921E", "^t c #F88B1B", "/t c #FFAB1E", "(t c #F99C1B", "_t c #B07625", ":t c #71512B", "u c #FFB322", ",u c #FFA51B", "'u c #F99D1B", ")u c #B07226", "!u c #71482E", "~u c #7F542A", "{u c #7D5529", "]u c #002D59", "^u c #08539B", "/u c #1E69A4", "(u c #296B9A", "_u c #2A71A2", ":u c #2F74A4", "v c #286C9D", ",v c #2B74A7", "'v c #2C73A5", ")v c #367CAD", "!v c #3880B2", "~v c #408EC1", "{v c #428FC5", "]v c #3E86BB", "^v c #408ABF", "/v c #448FC5", "(v c #4590C7", "_v c #4A93CD", ":v c #4B97CE", "w c #519CD8", ",w c #529EDB", "'w c #54A0DF", ")w c #56A1E0", "!w c #57A2E1", "~w c #59A4E4", "{w c #5BA7EA", "]w c #5DA9EE", "^w c #78DAFF", "/w c #6FD8FF", "(w c #60B2FD", "_w c #5FACF3", ":w c #5BA7E8", "x c #529EE0", ",x c #4FA3E7", "'x c #93D6F9", ")x c #7AD8FE", "!x c #4EB8FC", "~x c #5CBBF8", "{x c #60C9F9", "]x c #66D0FA", "^x c #8BD7F9", "/x c #C2F0FD", "(x c #D5FFFF", "_x c #CCFFFF", ":x c #B7F6FD", "y c #5AB7E7", ",y c #60C1EB", "'y c #4BB0E5", ")y c #3A9CDB", "!y c #3686C4", "~y c #3279B0", "{y c #2E73A4", "]y c #2A6998", "^y c #2E78A5", "/y c #1F6598", "(y c #1967AA", "_y c #627F8B", ":y c #B88B4E", "z c #7E482B", ",z c #013468", "'z c #0B5CA6", ")z c #206AA2", "!z c #286895", "~z c #296EA0", "{z c #296B9B", "]z c #337BAD", "^z c #3880B3", "/z c #3B83B4", "(z c #438CC3", "_z c #4790C9", ":z c #51A0D9", "A c #539CD8", ",A c #4F99D5", "'A c #4D98D1", ")A c #4B94CF", "!A c #4395D7", "~A c #73C2EE", "{A c #D4FAFE", "]A c #DAF7FE", "^A c #8ED9F5", "/A c #3E95D4", "(A c #3C85C0", "_A c #458BBE", ":A c #4187BA", "B c #2D719F", ",B c #367BAC", "'B c #387CAF", ")B c #3F89BE", "!B c #4188BE", "~B c #438DC2", "{B c #458EC4", "]B c #478FC7", "^B c #4B95CE", "/B c #4D97D1", "(B c #4D98D2", "_B c #4E98D4", ":B c #4F98D5", "C c #FFCC29", ",C c #FFD12D", "'C c #FFB81E", ")C c #FEB624", "!C c #FA9E1D", "~C c #B55D28", "{C c #6D2431", "]C c #73282F", "^C c #722A2E", "/C c #000C17", "(C c #00284F", "_C c #055398", ":C c #266794", "D c #4792C9", ",D c #4190CF", "'D c #42A3E1", ")D c #A1E8FA", "!D c #C3F3FC", "~D c #58A4DA", "{D c #3381B9", "]D c #3D83B8", "^D c #3A80B4", "/D c #3C89B9", "(D c #3F8DB9", "_D c #2C6E9F", ":D c #236494", "E c #71282E", ",E c #000207", "'E c #0756A0", ")E c #1B66A1", "!E c #286894", "~E c #2971A4", "{E c #2E79AB", "]E c #3781AC", "^E c #367EA8", "/E c #337CAC", "(E c #377CAD", "_E c #397EB1", ":E c #3B83B6", "F c #B3F8FF", ",F c #DBF8FD", "'F c #6FC0ED", ")F c #3690D5", "!F c #3F8CCD", "~F c #3E8ACA", "{F c #3E8DCE", "]F c #53A7DC", "^F c #82D8F2", "/F c #A5EFFE", "(F c #97D7F1", "_F c #70B2DC", ":F c #509ED3", "G c #2A75A9", ",G c #196AA6", "'G c #1C6BAE", ")G c #5D7789", "!G c #9B784D", "~G c #C17629", "{G c #EA871E", "]G c #FEA21C", "^G c #FEB21D", "/G c #B06F28", "(G c #723731", "_G c #7C3430", ":G c #7A2E2F", "H c #4292D2", ",H c #458ABF", "'H c #438BC0", ")H c #3784C0", "!H c #3389CD", "~H c #58B0E6", "{H c #BFF4FD", "]H c #9FF3FF", "^H c #43B8EF", "/H c #388ACC", "(H c #3C87B9", "_H c #367BAD", ":H c #3E8CBB", "I c #002042", ",I c #004283", "'I c #0E62AB", ")I c #2778AE", "!I c #2E79A6", "~I c #2D72A3", "{I c #3074A3", "]I c #3987B7", "^I c #4093C6", "/I c #4096CD", "(I c #428BCA", "_I c #2093DC", ":I c #93DBF6", "J c #317BAF", ",J c #3176A4", "'J c #367DAA", ")J c #317CAE", "!J c #2870A4", "~J c #276B9D", "{J c #2B74A2", "]J c #2472A7", "^J c #1264AC", "/J c #266EAA", "(J c #718F86", "_J c #BC924C", ":J c #E7912B", "K c #286896", ",K c #256491", "'K c #25699A", ")K c #307BAB", "!K c #327FC1", "~K c #30A0EA", "{K c #8FF3FF", "]K c #80E4FA", "^K c #3C97D4", "/K c #2E79B5", "(K c #3276AB", "_K c #387DAF", ":K c #377EAE", "L c #276B9A", ",L c #236493", "'L c #155E99", ")L c #1265AA", "!L c #377BA5", "~L c #7F987E", "{L c #C0AC4F", "]L c #E7B031", "^L c #F8B527", "/L c #FEBA23", "(L c #FFB722", "_L c #FB9419", ":L c #FC9117", "M c #3388C0", ",M c #3079AC", "'M c #3277A9", ")M c #3178AA", "!M c #3988BC", "~M c #348FCF", "{M c #3FBDED", "]M c #7CDCFA", "^M c #92E2F6", "/M c #8EECF9", "(M c #A9F6FF", "_M c #A4ECFE", ":M c #6ED5FC", "N c #71462C", ",N c #7E4A2C", "'N c #00050B", ")N c #001E3B", "!N c #003567", "~N c #034D93", "{N c #0D60AA", "]N c #1C68A6", "^N c #246191", "/N c #186AA5", "(N c #5FBDE5", "_N c #ABF1FF", ":N c #4AAFE3", "O c #1764A5", ",O c #2470A8", "'O c #4B8299", ")O c #81977A", "!O c #B3AD5A", "~O c #D7B940", "{O c #EEB92E", "]O c #F9B422", "^O c #FFBE26", "/O c #FEA219", "(O c #FEC224", "_O c #FEA71B", ":O c #FFA91B", "P c #B2FFFE", ",P c #CDFDFF", "'P c #6CDBF8", ")P c #2D99D7", "!P c #2E77AE", "~P c #246797", "{P c #1C6195", "]P c #1866A4", "^P c #176EB4", "/P c #1B6DB0", "(P c #2E72A5", "_P c #4F8298", ":P c #799280", "